From b5842614271d62b16cf030cbc6add0c3afdf1ade Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Mon, 31 Aug 2009 18:50:38 +0100 Subject: [PATCH] Add a new 'flow-monitor' module. --- src/contrib/flow-monitor/design.txt | 43 ++ src/contrib/flow-monitor/flow-classifier.cc | 40 ++ src/contrib/flow-monitor/flow-classifier.h | 52 ++ src/contrib/flow-monitor/flow-monitor.cc | 468 ++++++++++++++++++ src/contrib/flow-monitor/flow-monitor.h | 138 ++++++ src/contrib/flow-monitor/flow-probe.cc | 111 +++++ src/contrib/flow-monitor/flow-probe.h | 74 +++ src/contrib/flow-monitor/histogram.cc | 212 ++++++++ src/contrib/flow-monitor/histogram.h | 64 +++ .../flow-monitor/ipv4-flow-classifier.cc | 203 ++++++++ .../flow-monitor/ipv4-flow-classifier.h | 74 +++ src/contrib/flow-monitor/ipv4-flow-probe.cc | 178 +++++++ src/contrib/flow-monitor/ipv4-flow-probe.h | 64 +++ src/contrib/flow-monitor/waf | 2 + src/contrib/flow-monitor/wscript | 23 + src/helper/flow-monitor-helper.cc | 110 ++++ src/helper/flow-monitor-helper.h | 56 +++ src/helper/wscript | 2 + src/wscript | 1 + 19 files changed, 1915 insertions(+) create mode 100644 src/contrib/flow-monitor/design.txt create mode 100644 src/contrib/flow-monitor/flow-classifier.cc create mode 100644 src/contrib/flow-monitor/flow-classifier.h create mode 100644 src/contrib/flow-monitor/flow-monitor.cc create mode 100644 src/contrib/flow-monitor/flow-monitor.h create mode 100644 src/contrib/flow-monitor/flow-probe.cc create mode 100644 src/contrib/flow-monitor/flow-probe.h create mode 100644 src/contrib/flow-monitor/histogram.cc create mode 100644 src/contrib/flow-monitor/histogram.h create mode 100644 src/contrib/flow-monitor/ipv4-flow-classifier.cc create mode 100644 src/contrib/flow-monitor/ipv4-flow-classifier.h create mode 100644 src/contrib/flow-monitor/ipv4-flow-probe.cc create mode 100644 src/contrib/flow-monitor/ipv4-flow-probe.h create mode 100755 src/contrib/flow-monitor/waf create mode 100644 src/contrib/flow-monitor/wscript create mode 100644 src/helper/flow-monitor-helper.cc create mode 100644 src/helper/flow-monitor-helper.h diff --git a/src/contrib/flow-monitor/design.txt b/src/contrib/flow-monitor/design.txt new file mode 100644 index 000000000..1d711342b --- /dev/null +++ b/src/contrib/flow-monitor/design.txt @@ -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 + diff --git a/src/contrib/flow-monitor/flow-classifier.cc b/src/contrib/flow-monitor/flow-classifier.cc new file mode 100644 index 000000000..fb184101f --- /dev/null +++ b/src/contrib/flow-monitor/flow-classifier.cc @@ -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 +// + +#include "flow-classifier.h" + +namespace ns3 { + +FlowClassifier::FlowClassifier () + : + m_lastNewFlowId (0) +{ +} + + +FlowId +FlowClassifier::GetNewFlowId () +{ + return ++m_lastNewFlowId; +} + + +} // namespace ns3 + diff --git a/src/contrib/flow-monitor/flow-classifier.h b/src/contrib/flow-monitor/flow-classifier.h new file mode 100644 index 000000000..0029ef771 --- /dev/null +++ b/src/contrib/flow-monitor/flow-classifier.h @@ -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 +// + +#ifndef __FLOW_CLASSIFIER_H__ +#define __FLOW_CLASSIFIER_H__ + +#include "ns3/ref-count-base.h" +#include + +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 + diff --git a/src/contrib/flow-monitor/flow-monitor.cc b/src/contrib/flow-monitor/flow-monitor.cc new file mode 100644 index 000000000..9a6536f25 --- /dev/null +++ b/src/contrib/flow-monitor/flow-monitor.cc @@ -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 +// + +#include "flow-monitor.h" +#include "ns3/simulator.h" +#include "ns3/log.h" +#include "ns3/double.h" +#include +#include + +#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 () + .AddConstructor () + .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 ()) + .AddAttribute ("JitterBinWidth", ("The width used in the jitter histogram."), + DoubleValue (0.001), + MakeDoubleAccessor (&FlowMonitor::m_jitterBinWidth), + MakeDoubleChecker ()) + .AddAttribute ("PacketSizeBinWidth", ("The width used in the packetSize histogram."), + DoubleValue (20), + MakeDoubleAccessor (&FlowMonitor::m_packetSizeBinWidth), + MakeDoubleChecker ()) + ; + 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::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 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 probe, uint32_t flowId, uint32_t packetId, uint32_t packetSize) +{ + if (!m_enabled) + { + return; + } + std::pair 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 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 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 +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::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 probe) +{ + m_flowProbes.push_back (probe); +} + +std::vector< Ptr > +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 (this)); +} + +void +FlowMonitor::Stop (const Time &time) +{ + if (!m_enabled) + { + return; + } + Simulator::Cancel (m_stopEvent); + m_stopEvent = Simulator::Schedule (time, &FlowMonitor::StopRightNow, Ptr (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 classifier) +{ + m_classifier = classifier; +} + +void +FlowMonitor::SerializeToXmlStream (std::ostream &os, int indent, bool enableHistograms, bool enableProbes) +{ + CheckForLostPackets (); + + INDENT(indent); os << "\n"; + indent += 2; + INDENT(indent); os << "\n"; + indent += 2; + for (std::map::const_iterator flowI = m_flowStats.begin (); + flowI != m_flowStats.end (); flowI++) + { + + INDENT(indent); +#define ATTRIB(name) << " "#name"=\"" << flowI->second.name << "\"" + os << "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 << "second.packetsDropped[reasonCode] + << "\" />\n"; + } + for (uint32_t reasonCode = 0; reasonCode < flowI->second.bytesDropped.size (); reasonCode++) + { + INDENT(indent); + os << "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 << "\n"; + } + indent -= 2; + INDENT(indent); os << "\n"; + + m_classifier->SerializeToXmlStream (os, indent); + + if (enableProbes) + { + INDENT(indent); os << "\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 << "\n"; + } + + indent -= 2; + INDENT(indent); os << "\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 << "\n"; + SerializeToXmlStream (os, 0, enableHistograms, enableProbes); + os.close (); +} + + +} // namespace ns3 + diff --git a/src/contrib/flow-monitor/flow-monitor.h b/src/contrib/flow-monitor/flow-monitor.h new file mode 100644 index 000000000..d1acc8fcc --- /dev/null +++ b/src/contrib/flow-monitor/flow-monitor.h @@ -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 +// + +#ifndef __FLOW_MONITOR_H__ +#define __FLOW_MONITOR_H__ + +#include +#include + +#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 packetsDropped; // packetsDropped[reasonCode] => number of dropped packets + std::vector bytesDropped; // bytesDropped[reasonCode] => number of dropped bytes + }; + + // --- basic methods --- + static TypeId GetTypeId (); + TypeId GetInstanceTypeId () const; + FlowMonitor (); + void SetFlowClassifier (Ptr 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 probe); + void ReportFirstTx (Ptr probe, FlowId flowId, FlowPacketId packetId, uint32_t packetSize); + void ReportForwarding (Ptr probe, FlowId flowId, FlowPacketId packetId, uint32_t packetSize); + void ReportLastRx (Ptr probe, FlowId flowId, FlowPacketId packetId, uint32_t packetSize); + void ReportDrop (Ptr 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 GetFlowStats () const; + std::vector< Ptr > 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 m_flowStats; + + // (FlowId,PacketId) --> TrackedPacket + typedef std::map< std::pair, TrackedPacket> TrackedPacketMap; + TrackedPacketMap m_trackedPackets; + Time m_maxPerHopDelay; + std::vector< Ptr > m_flowProbes; + + // note: this is needed only for serialization + Ptr 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 + diff --git a/src/contrib/flow-monitor/flow-probe.cc b/src/contrib/flow-monitor/flow-probe.cc new file mode 100644 index 000000000..e58058942 --- /dev/null +++ b/src/contrib/flow-monitor/flow-probe.cc @@ -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 +// + +#include "ns3/flow-probe.h" +#include "ns3/flow-monitor.h" + +namespace ns3 { + + +FlowProbe::~FlowProbe () +{ +} + + +FlowProbe::FlowProbe (Ptr 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 << "\n"; + + indent += 2; + + for (Stats::const_iterator iter = m_stats.begin (); iter != m_stats.end (); iter++) + { + INDENT(indent); + os << "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 << "second.packetsDropped[reasonCode] + << "\" />\n"; + } + for (uint32_t reasonCode = 0; reasonCode < iter->second.bytesDropped.size (); reasonCode++) + { + INDENT(indent); + os << "second.bytesDropped[reasonCode] + << "\" />\n"; + } + indent -= 2; + INDENT(indent); os << "\n"; + } + indent -= 2; + INDENT(indent); os << "\n"; +} + + + +} // namespace ns3 + + diff --git a/src/contrib/flow-monitor/flow-probe.h b/src/contrib/flow-monitor/flow-probe.h new file mode 100644 index 000000000..3b86f16b7 --- /dev/null +++ b/src/contrib/flow-monitor/flow-probe.h @@ -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 +// + +#ifndef __FLOW_PROBE_H__ +#define __FLOW_PROBE_H__ + +#include +#include + +#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); + +public: + ~FlowProbe (); + + struct FlowStats + { + FlowStats () : delayFromFirstProbeSum (Seconds (0)), bytes (0), packets (0) {} + + std::vector packetsDropped; // packetsDropped[reasonCode] => number of dropped packets + std::vector 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 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 m_flowMonitor; + Stats m_stats; + +}; + + +} // namespace ns3 + +#endif + diff --git a/src/contrib/flow-monitor/histogram.cc b/src/contrib/flow-monitor/histogram.cc new file mode 100644 index 000000000..ec1b31190 --- /dev/null +++ b/src/contrib/flow-monitor/histogram.cc @@ -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 +// + +#include +#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 << "\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 << "\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 */ + diff --git a/src/contrib/flow-monitor/histogram.h b/src/contrib/flow-monitor/histogram.h new file mode 100644 index 000000000..6772e1675 --- /dev/null +++ b/src/contrib/flow-monitor/histogram.h @@ -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 +// + +#ifndef __NS3_HISTOGRAM_H__ +#define __NS3_HISTOGRAM_H__ + +#include +#include +#include + +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 m_histogram; + double m_binWidth; +}; + + +} // namespace ns3 + +#endif + diff --git a/src/contrib/flow-monitor/ipv4-flow-classifier.cc b/src/contrib/flow-monitor/ipv4-flow-classifier.cc new file mode 100644 index 000000000..e0692bf21 --- /dev/null +++ b/src/contrib/flow-monitor/ipv4-flow-classifier.cc @@ -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 +// + +#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 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::iterator, bool> insert + = m_flowMap.insert (std::pair (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::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 << "\n"; + + indent += 2; + for (std::map::const_iterator + iter = m_flowMap.begin (); iter != m_flowMap.end (); iter++) + { + INDENT(indent); + os << "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 << "\n"; + +#undef INDENT +} + + +} // namespace ns3 + diff --git a/src/contrib/flow-monitor/ipv4-flow-classifier.h b/src/contrib/flow-monitor/ipv4-flow-classifier.h new file mode 100644 index 000000000..fff4baa71 --- /dev/null +++ b/src/contrib/flow-monitor/ipv4-flow-classifier.h @@ -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 +// + +#ifndef __IPV4_FLOW_CLASSIFIER_H__ +#define __IPV4_FLOW_CLASSIFIER_H__ + +#include +#include + +#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 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 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 + diff --git a/src/contrib/flow-monitor/ipv4-flow-probe.cc b/src/contrib/flow-monitor/ipv4-flow-probe.cc new file mode 100644 index 000000000..1139641ec --- /dev/null +++ b/src/contrib/flow-monitor/ipv4-flow-probe.cc @@ -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 +// + +#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 monitor, + Ptr classifier, + Ptr node) + : FlowProbe (monitor), + m_classifier (classifier) +{ + NS_LOG_FUNCTION (this << node->GetId ()); + + Ptr ipv4 = node->GetObject (); + + if (!ipv4->TraceConnectWithoutContext ("SendOutgoing", + MakeCallback (&Ipv4FlowProbe::SendOutgoingLogger, Ptr (this)))) + { + NS_FATAL_ERROR ("trace fail"); + } + if (!ipv4->TraceConnectWithoutContext ("UnicastForward", + MakeCallback (&Ipv4FlowProbe::ForwardLogger, Ptr (this)))) + { + NS_FATAL_ERROR ("trace fail"); + } + if (!ipv4->TraceConnectWithoutContext ("LocalDeliver", + MakeCallback (&Ipv4FlowProbe::ForwardUpLogger, Ptr (this)))) + { + NS_FATAL_ERROR ("trace fail"); + } + + if (!ipv4->TraceConnectWithoutContext ("Drop", + MakeCallback (&Ipv4FlowProbe::DropLogger, Ptr (this)))) + { + NS_FATAL_ERROR ("trace fail"); + } +} + +void +Ipv4FlowProbe::SendOutgoingLogger (const Ipv4Header &ipHeader, Ptr 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 ("<ReportFirstTx (this, flowId, packetId, size); + } +} + +void +Ipv4FlowProbe::ForwardLogger (const Ipv4Header &ipHeader, Ptr 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 ("<ReportForwarding (this, flowId, packetId, size); + } + +} + +void +Ipv4FlowProbe::ForwardUpLogger (const Ipv4Header &ipHeader, Ptr 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 ("<ReportLastRx (this, flowId, packetId, size); + } +} + +void +Ipv4FlowProbe::DropLogger (const Ipv4Header &ipHeader, Ptr 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 ("<ReportDrop (this, flowId, packetId, size, myReason); + } +} + + + +} // namespace ns3 + + diff --git a/src/contrib/flow-monitor/ipv4-flow-probe.h b/src/contrib/flow-monitor/ipv4-flow-probe.h new file mode 100644 index 000000000..4248f771e --- /dev/null +++ b/src/contrib/flow-monitor/ipv4-flow-probe.h @@ -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 +// + +#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 monitor, Ptr classifier, Ptr 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 ipPayload, uint32_t interface); + void ForwardLogger (const Ipv4Header &ipHeader, Ptr ipPayload, uint32_t interface); + void ForwardUpLogger (const Ipv4Header &ipHeader, Ptr ipPayload, uint32_t interface); + void DropLogger (const Ipv4Header &ipHeader, Ptr ipPayload, + Ipv4L3Protocol::DropReason reason, uint32_t ifIndex); + + Ptr m_classifier; +}; + + +} // namespace ns3 + +#endif + diff --git a/src/contrib/flow-monitor/waf b/src/contrib/flow-monitor/waf new file mode 100755 index 000000000..51f099826 --- /dev/null +++ b/src/contrib/flow-monitor/waf @@ -0,0 +1,2 @@ +#! /bin/sh +exec "`dirname "$0"`"/../../../waf "$@" diff --git a/src/contrib/flow-monitor/wscript b/src/contrib/flow-monitor/wscript new file mode 100644 index 000000000..71872a8da --- /dev/null +++ b/src/contrib/flow-monitor/wscript @@ -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', + ] + diff --git a/src/helper/flow-monitor-helper.cc b/src/helper/flow-monitor-helper.cc new file mode 100644 index 000000000..72c2bc0d0 --- /dev/null +++ b/src/helper/flow-monitor-helper.cc @@ -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 +// + +#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 +FlowMonitorHelper::GetMonitor () +{ + if (!m_flowMonitor) + { + m_flowMonitor = m_monitorFactory.Create (); + m_flowClassifier = Create (); + m_flowMonitor->SetFlowClassifier (m_flowClassifier); + } + return m_flowMonitor; +} + + +Ptr +FlowMonitorHelper::GetClassifier () +{ + if (!m_flowClassifier) + { + m_flowClassifier = Create (); + } + return m_flowClassifier; +} + + +Ptr +FlowMonitorHelper::Install (Ptr node) +{ + Ptr monitor = GetMonitor (); + Ptr classifier = GetClassifier (); + Ptr probe = Create (monitor, + DynamicCast (classifier), + node); + return m_flowMonitor; +} + + +Ptr +FlowMonitorHelper::Install (NodeContainer nodes) +{ + for (NodeContainer::Iterator i = nodes.Begin (); i != nodes.End (); ++i) + { + Ptr node = *i; + if (node->GetObject ()) + { + Install (node); + } + } + return m_flowMonitor; +} + +Ptr +FlowMonitorHelper::InstallAll () +{ + for (NodeList::Iterator i = NodeList::Begin (); i != NodeList::End (); ++i) + { + Ptr node = *i; + if (node->GetObject ()) + { + Install (node); + } + } + return m_flowMonitor; +} + + +} // namespace ns3 diff --git a/src/helper/flow-monitor-helper.h b/src/helper/flow-monitor-helper.h new file mode 100644 index 000000000..bdd4e99ac --- /dev/null +++ b/src/helper/flow-monitor-helper.h @@ -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 +// +#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 + +namespace ns3 { + +class AttributeValue; +class Ipv4FlowClassifier; + +class FlowMonitorHelper +{ +public: + FlowMonitorHelper (); + void SetMonitorAttribute (std::string n1, const AttributeValue &v1); + + Ptr Install (NodeContainer nodes); + Ptr Install (Ptr node); + Ptr InstallAll (); + + Ptr GetMonitor (); + Ptr GetClassifier (); + +private: + ObjectFactory m_monitorFactory; + Ptr m_flowMonitor; + Ptr m_flowClassifier; +}; + +} // namespace ns3 + + +#endif /* FLOW_MONITOR_HELPER_H */ diff --git a/src/helper/wscript b/src/helper/wscript index 3ced3f13a..142d90a46 100644 --- a/src/helper/wscript +++ b/src/helper/wscript @@ -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') diff --git a/src/wscript b/src/wscript index fcc57038a..27d011b14 100644 --- a/src/wscript +++ b/src/wscript @@ -38,6 +38,7 @@ all_modules = ( 'applications/v4ping', 'applications/ping6', 'applications/radvd', + 'contrib/flow-monitor', ) def set_options(opt):