Adapt the flow-monitor module to the new module tree layout spec.
authorGustavo J. A. M. Carneiro <gjc@inescporto.pt>
Fri, 22 Oct 2010 17:18:49 +0100
changeset 6631 2fd8e12e635d
parent 6630 014fcf11568e
child 6632 1f0ce8e8a810
Adapt the flow-monitor module to the new module tree layout spec.
examples/flowmon/flowmon-parse-results.py
examples/flowmon/waf
examples/flowmon/wifi-olsr-flowmon.py
examples/flowmon/wscript
src/contrib/flow-monitor/design.txt
src/contrib/flow-monitor/doc/design.txt
src/contrib/flow-monitor/examples/flowmon-parse-results.py
src/contrib/flow-monitor/examples/wifi-olsr-flowmon.py
src/contrib/flow-monitor/flow-classifier.cc
src/contrib/flow-monitor/flow-classifier.h
src/contrib/flow-monitor/flow-monitor.cc
src/contrib/flow-monitor/flow-monitor.h
src/contrib/flow-monitor/flow-probe.cc
src/contrib/flow-monitor/flow-probe.h
src/contrib/flow-monitor/helper/flow-monitor-helper.cc
src/contrib/flow-monitor/helper/flow-monitor-helper.h
src/contrib/flow-monitor/histogram.cc
src/contrib/flow-monitor/histogram.h
src/contrib/flow-monitor/ipv4-flow-classifier.cc
src/contrib/flow-monitor/ipv4-flow-classifier.h
src/contrib/flow-monitor/ipv4-flow-probe.cc
src/contrib/flow-monitor/ipv4-flow-probe.h
src/contrib/flow-monitor/model/flow-classifier.cc
src/contrib/flow-monitor/model/flow-classifier.h
src/contrib/flow-monitor/model/flow-monitor.cc
src/contrib/flow-monitor/model/flow-monitor.h
src/contrib/flow-monitor/model/flow-probe.cc
src/contrib/flow-monitor/model/flow-probe.h
src/contrib/flow-monitor/model/histogram.cc
src/contrib/flow-monitor/model/histogram.h
src/contrib/flow-monitor/model/ipv4-flow-classifier.cc
src/contrib/flow-monitor/model/ipv4-flow-classifier.h
src/contrib/flow-monitor/model/ipv4-flow-probe.cc
src/contrib/flow-monitor/model/ipv4-flow-probe.h
src/contrib/flow-monitor/wscript
src/helper/flow-monitor-helper.cc
src/helper/flow-monitor-helper.h
src/helper/wscript
--- a/examples/flowmon/flowmon-parse-results.py	Fri Oct 22 14:59:56 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,143 +0,0 @@
-from __future__ import division
-import sys
-import os
-try:
-    from xml.etree import cElementTree as ElementTree
-except ImportError:
-    from xml.etree import ElementTree
-
-def parse_time_ns(tm):
-    if tm.endswith('ns'):
-        return long(tm[:-2])
-    raise ValueError(tm)
-
-
-
-class FiveTuple(object):
-    __slots__ = ['sourceAddress', 'destinationAddress', 'protocol', 'sourcePort', 'destinationPort']
-    def __init__(self, el):
-        self.sourceAddress = el.get('sourceAddress')
-        self.destinationAddress = el.get('destinationAddress')
-        self.sourcePort = int(el.get('sourcePort'))
-        self.destinationPort = int(el.get('destinationPort'))
-        self.protocol = int(el.get('protocol'))
-        
-class Histogram(object):
-    __slots__ = 'bins', 'nbins', 'number_of_flows'
-    def __init__(self, el=None):
-        self.bins = []
-        if el is not None:
-            #self.nbins = int(el.get('nBins'))
-            for bin in el.findall('bin'):
-                self.bins.append( (float(bin.get("start")), float(bin.get("width")), int(bin.get("count"))) )
-
-class Flow(object):
-    __slots__ = ['flowId', 'delayMean', 'packetLossRatio', 'rxBitrate', 'txBitrate',
-                 'fiveTuple', 'packetSizeMean', 'probe_stats_unsorted',
-                 'hopCount', 'flowInterruptionsHistogram', 'rx_duration']
-    def __init__(self, flow_el):
-        self.flowId = int(flow_el.get('flowId'))
-        rxPackets = long(flow_el.get('rxPackets'))
-        txPackets = long(flow_el.get('txPackets'))
-        tx_duration = float(long(flow_el.get('timeLastTxPacket')[:-2]) - long(flow_el.get('timeFirstTxPacket')[:-2]))*1e-9
-        rx_duration = float(long(flow_el.get('timeLastRxPacket')[:-2]) - long(flow_el.get('timeFirstRxPacket')[:-2]))*1e-9
-        self.rx_duration = rx_duration
-        self.probe_stats_unsorted = []
-        if rxPackets:
-            self.hopCount = float(flow_el.get('timesForwarded')) / rxPackets + 1
-        else:
-            self.hopCount = -1000
-        if rxPackets:
-            self.delayMean = float(flow_el.get('delaySum')[:-2]) / rxPackets * 1e-9
-            self.packetSizeMean = float(flow_el.get('rxBytes')) / rxPackets
-        else:
-            self.delayMean = None
-            self.packetSizeMean = None
-        if rx_duration > 0:
-            self.rxBitrate = long(flow_el.get('rxBytes'))*8 / rx_duration
-        else:
-            self.rxBitrate = None
-        if tx_duration > 0:
-            self.txBitrate = long(flow_el.get('txBytes'))*8 / tx_duration
-        else:
-            self.txBitrate = None
-        lost = float(flow_el.get('lostPackets'))
-        #print "rxBytes: %s; txPackets: %s; rxPackets: %s; lostPackets: %s" % (flow_el.get('rxBytes'), txPackets, rxPackets, lost)
-        if rxPackets == 0:
-            self.packetLossRatio = None
-        else:
-            self.packetLossRatio = (lost / (rxPackets + lost))
-
-        interrupt_hist_elem = flow_el.find("flowInterruptionsHistogram")
-        if interrupt_hist_elem is None:
-            self.flowInterruptionsHistogram = None
-        else:
-            self.flowInterruptionsHistogram = Histogram(interrupt_hist_elem)
-
-
-class ProbeFlowStats(object):
-    __slots__ = ['probeId', 'packets', 'bytes', 'delayFromFirstProbe']
-
-class Simulation(object):
-    def __init__(self, simulation_el):
-        self.flows = []
-        FlowClassifier_el, = simulation_el.findall("Ipv4FlowClassifier")
-        flow_map = {}
-        for flow_el in simulation_el.findall("FlowStats/Flow"):
-            flow = Flow(flow_el)
-            flow_map[flow.flowId] = flow
-            self.flows.append(flow)
-        for flow_cls in FlowClassifier_el.findall("Flow"):
-            flowId = int(flow_cls.get('flowId'))
-            flow_map[flowId].fiveTuple = FiveTuple(flow_cls)
-
-        for probe_elem in simulation_el.findall("FlowProbes/FlowProbe"):
-            probeId = int(probe_elem.get('index'))
-            for stats in probe_elem.findall("FlowStats"):
-                flowId = int(stats.get('flowId'))
-                s = ProbeFlowStats()
-                s.packets = int(stats.get('packets'))
-                s.bytes = long(stats.get('bytes'))
-                s.probeId = probeId
-                if s.packets > 0:
-                    s.delayFromFirstProbe =  parse_time_ns(stats.get('delayFromFirstProbeSum')) / float(s.packets)
-                else:
-                    s.delayFromFirstProbe = 0
-                flow_map[flowId].probe_stats_unsorted.append(s)
-
-
-def main(argv):
-    file_obj = open(argv[1])
-    print "Reading XML file ",
- 
-    sys.stdout.flush()        
-    level = 0
-    sim_list = []
-    for event, elem in ElementTree.iterparse(file_obj, events=("start", "end")):
-        if event == "start":
-            level += 1
-        if event == "end":
-            level -= 1
-            if level == 0 and elem.tag == 'FlowMonitor':
-                sim = Simulation(elem)
-                sim_list.append(sim)
-                elem.clear() # won't need this any more
-                sys.stdout.write(".")
-                sys.stdout.flush()
-    print " done."
-
-
-    for sim in sim_list:
-        for flow in sim.flows:
-            t = flow.fiveTuple
-            proto = {6: 'TCP', 17: 'UDP'} [t.protocol]
-            print "FlowID: %i (%s %s/%s --> %s/%i)" % \
-                (flow.flowId, proto, t.sourceAddress, t.sourcePort, t.destinationAddress, t.destinationPort)
-            print "\tTX bitrate: %.2f kbit/s" % (flow.txBitrate*1e-3,)
-            print "\tRX bitrate: %.2f kbit/s" % (flow.rxBitrate*1e-3,)
-            print "\tMean Delay: %.2f ms" % (flow.delayMean*1e3,)
-            print "\tPacket Loss Ratio: %.2f %%" % (flow.packetLossRatio*100)
-
-
-if __name__ == '__main__':
-    main(sys.argv)
--- a/examples/flowmon/waf	Fri Oct 22 14:59:56 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-exec "`dirname "$0"`"/../../waf "$@"
--- a/examples/flowmon/wifi-olsr-flowmon.py	Fri Oct 22 14:59:56 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,171 +0,0 @@
-# -*-  Mode: Python; -*-
-#  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
-# 
-#  Authors: Gustavo Carneiro <gjc@inescporto.pt>
-
-import sys
-import ns3
-
-DISTANCE = 100 # (m)
-NUM_NODES_SIDE = 3
-
-def main(argv):
-
-    cmd = ns3.CommandLine()
-
-    cmd.NumNodesSide = None
-    cmd.AddValue("NumNodesSide", "Grid side number of nodes (total number of nodes will be this number squared)")
-
-    cmd.Results = None
-    cmd.AddValue("Results", "Write XML results to file")
-
-    cmd.Plot = None
-    cmd.AddValue("Plot", "Plot the results using the matplotlib python module")
-
-    cmd.Parse(argv)
-
-    wifi = ns3.WifiHelper.Default()
-    wifiMac = ns3.NqosWifiMacHelper.Default()
-    wifiPhy = ns3.YansWifiPhyHelper.Default()
-    wifiChannel = ns3.YansWifiChannelHelper.Default()
-    wifiPhy.SetChannel(wifiChannel.Create())
-    ssid = ns3.Ssid("wifi-default")
-    wifi.SetRemoteStationManager("ns3::ArfWifiManager")
-    wifiMac.SetType ("ns3::AdhocWifiMac", "Ssid", ns3.SsidValue(ssid))
-
-    internet = ns3.InternetStackHelper()
-    list_routing = ns3.Ipv4ListRoutingHelper()
-    olsr_routing = ns3.OlsrHelper()
-    static_routing = ns3.Ipv4StaticRoutingHelper()
-    list_routing.Add(static_routing, 0)
-    list_routing.Add(olsr_routing, 100)
-    internet.SetRoutingHelper(list_routing)
-
-    ipv4Addresses = ns3.Ipv4AddressHelper()
-    ipv4Addresses.SetBase(ns3.Ipv4Address("10.0.0.0"), ns3.Ipv4Mask("255.255.255.0"))
-
-    port = 9   # Discard port(RFC 863)
-    onOffHelper = ns3.OnOffHelper("ns3::UdpSocketFactory",
-                                  ns3.Address(ns3.InetSocketAddress(ns3.Ipv4Address("10.0.0.1"), port)))
-    onOffHelper.SetAttribute("DataRate", ns3.DataRateValue(ns3.DataRate("100kbps")))
-    onOffHelper.SetAttribute("OnTime", ns3.RandomVariableValue(ns3.ConstantVariable(1)))
-    onOffHelper.SetAttribute("OffTime", ns3.RandomVariableValue(ns3.ConstantVariable(0)))
-
-    addresses = []
-    nodes = []
-
-    if cmd.NumNodesSide is None:
-        num_nodes_side = NUM_NODES_SIDE
-    else:
-        num_nodes_side = int(cmd.NumNodesSide)
-
-    for xi in range(num_nodes_side):
-        for yi in range(num_nodes_side):
-
-            node = ns3.Node()
-            nodes.append(node)
-
-            internet.Install(ns3.NodeContainer(node))
-
-            mobility = ns3.ConstantPositionMobilityModel()
-            mobility.SetPosition(ns3.Vector(xi*DISTANCE, yi*DISTANCE, 0))
-            node.AggregateObject(mobility)
-            
-            devices = wifi.Install(wifiPhy, wifiMac, node)
-            ipv4_interfaces = ipv4Addresses.Assign(devices)
-            addresses.append(ipv4_interfaces.GetAddress(0))
-
-    for i, node in enumerate(nodes):
-        destaddr = addresses[(len(addresses) - 1 - i) % len(addresses)]
-        #print i, destaddr
-        onOffHelper.SetAttribute("Remote", ns3.AddressValue(ns3.InetSocketAddress(destaddr, port)))
-        app = onOffHelper.Install(ns3.NodeContainer(node))
-        app.Start(ns3.Seconds(ns3.UniformVariable(20, 30).GetValue()))
-            
-    #internet.EnablePcapAll("wifi-olsr")
-    flowmon_helper = ns3.FlowMonitorHelper()
-    #flowmon_helper.SetMonitorAttribute("StartTime", ns3.TimeValue(ns3.Seconds(31)))
-    monitor = flowmon_helper.InstallAll()
-    monitor.SetAttribute("DelayBinWidth", ns3.DoubleValue(0.001))
-    monitor.SetAttribute("JitterBinWidth", ns3.DoubleValue(0.001))
-    monitor.SetAttribute("PacketSizeBinWidth", ns3.DoubleValue(20))
-
-    ns3.Simulator.Stop(ns3.Seconds(44.0))
-    ns3.Simulator.Run()
-
-    def print_stats(os, st):
-        print >> os, "  Tx Bytes: ", st.txBytes
-        print >> os, "  Rx Bytes: ", st.rxBytes
-        print >> os, "  Tx Packets: ", st.txPackets
-        print >> os, "  Rx Packets: ", st.rxPackets
-        print >> os, "  Lost Packets: ", st.lostPackets
-        if st.rxPackets > 0:
-            print >> os, "  Mean{Delay}: ", (st.delaySum.GetSeconds() / st.rxPackets)
-	    print >> os, "  Mean{Jitter}: ", (st.jitterSum.GetSeconds() / (st.rxPackets-1))
-            print >> os, "  Mean{Hop Count}: ", float(st.timesForwarded) / st.rxPackets + 1
-
-        if 0:
-            print >> os, "Delay Histogram"
-            for i in range(st.delayHistogram.GetNBins () ):
-              print >> os, " ",i,"(", st.delayHistogram.GetBinStart (i), "-", \
-                  st.delayHistogram.GetBinEnd (i), "): ", st.delayHistogram.GetBinCount (i)
-            print >> os, "Jitter Histogram"
-            for i in range(st.jitterHistogram.GetNBins () ):
-              print >> os, " ",i,"(", st.jitterHistogram.GetBinStart (i), "-", \
-                  st.jitterHistogram.GetBinEnd (i), "): ", st.jitterHistogram.GetBinCount (i)
-            print >> os, "PacketSize Histogram"
-            for i in range(st.packetSizeHistogram.GetNBins () ):
-              print >> os, " ",i,"(", st.packetSizeHistogram.GetBinStart (i), "-", \
-                  st.packetSizeHistogram.GetBinEnd (i), "): ", st.packetSizeHistogram.GetBinCount (i)
-
-        for reason, drops in enumerate(st.packetsDropped):
-            print "  Packets dropped by reason %i: %i" % (reason, drops)
-        #for reason, drops in enumerate(st.bytesDropped):
-        #    print "Bytes dropped by reason %i: %i" % (reason, drops)
-
-    monitor.CheckForLostPackets()
-    classifier = flowmon_helper.GetClassifier()
-
-    if cmd.Results is None:
-        for flow_id, flow_stats in monitor.GetFlowStats():
-            t = classifier.FindFlow(flow_id)
-            proto = {6: 'TCP', 17: 'UDP'} [t.protocol]
-            print "FlowID: %i (%s %s/%s --> %s/%i)" % \
-                (flow_id, proto, t.sourceAddress, t.sourcePort, t.destinationAddress, t.destinationPort)
-            print_stats(sys.stdout, flow_stats)
-    else:
-        print monitor.SerializeToXmlFile(cmd.Results, True, True)
-
-
-    if cmd.Plot is not None:
-        import pylab
-        delays = []
-        for flow_id, flow_stats in monitor.GetFlowStats():
-            tupl = classifier.FindFlow(flow_id)
-            if tupl.protocol == 17 and tupl.sourcePort == 698:
-                continue
-            delays.append(flow_stats.delaySum.GetSeconds() / flow_stats.rxPackets)
-        pylab.hist(delays, 20)
-        pylab.xlabel("Delay (s)")
-        pylab.ylabel("Number of Flows")
-        pylab.show()
-
-    return 0
-
-
-if __name__ == '__main__':
-    sys.exit(main(sys.argv))
-
--- a/examples/flowmon/wscript	Fri Oct 22 14:59:56 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-
-def build(bld):
-    pass
--- a/src/contrib/flow-monitor/design.txt	Fri Oct 22 14:59:56 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-
-* 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
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/flow-monitor/doc/design.txt	Fri Oct 22 17:18:49 2010 +0100
@@ -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
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/flow-monitor/examples/flowmon-parse-results.py	Fri Oct 22 17:18:49 2010 +0100
@@ -0,0 +1,143 @@
+from __future__ import division
+import sys
+import os
+try:
+    from xml.etree import cElementTree as ElementTree
+except ImportError:
+    from xml.etree import ElementTree
+
+def parse_time_ns(tm):
+    if tm.endswith('ns'):
+        return long(tm[:-2])
+    raise ValueError(tm)
+
+
+
+class FiveTuple(object):
+    __slots__ = ['sourceAddress', 'destinationAddress', 'protocol', 'sourcePort', 'destinationPort']
+    def __init__(self, el):
+        self.sourceAddress = el.get('sourceAddress')
+        self.destinationAddress = el.get('destinationAddress')
+        self.sourcePort = int(el.get('sourcePort'))
+        self.destinationPort = int(el.get('destinationPort'))
+        self.protocol = int(el.get('protocol'))
+        
+class Histogram(object):
+    __slots__ = 'bins', 'nbins', 'number_of_flows'
+    def __init__(self, el=None):
+        self.bins = []
+        if el is not None:
+            #self.nbins = int(el.get('nBins'))
+            for bin in el.findall('bin'):
+                self.bins.append( (float(bin.get("start")), float(bin.get("width")), int(bin.get("count"))) )
+
+class Flow(object):
+    __slots__ = ['flowId', 'delayMean', 'packetLossRatio', 'rxBitrate', 'txBitrate',
+                 'fiveTuple', 'packetSizeMean', 'probe_stats_unsorted',
+                 'hopCount', 'flowInterruptionsHistogram', 'rx_duration']
+    def __init__(self, flow_el):
+        self.flowId = int(flow_el.get('flowId'))
+        rxPackets = long(flow_el.get('rxPackets'))
+        txPackets = long(flow_el.get('txPackets'))
+        tx_duration = float(long(flow_el.get('timeLastTxPacket')[:-2]) - long(flow_el.get('timeFirstTxPacket')[:-2]))*1e-9
+        rx_duration = float(long(flow_el.get('timeLastRxPacket')[:-2]) - long(flow_el.get('timeFirstRxPacket')[:-2]))*1e-9
+        self.rx_duration = rx_duration
+        self.probe_stats_unsorted = []
+        if rxPackets:
+            self.hopCount = float(flow_el.get('timesForwarded')) / rxPackets + 1
+        else:
+            self.hopCount = -1000
+        if rxPackets:
+            self.delayMean = float(flow_el.get('delaySum')[:-2]) / rxPackets * 1e-9
+            self.packetSizeMean = float(flow_el.get('rxBytes')) / rxPackets
+        else:
+            self.delayMean = None
+            self.packetSizeMean = None
+        if rx_duration > 0:
+            self.rxBitrate = long(flow_el.get('rxBytes'))*8 / rx_duration
+        else:
+            self.rxBitrate = None
+        if tx_duration > 0:
+            self.txBitrate = long(flow_el.get('txBytes'))*8 / tx_duration
+        else:
+            self.txBitrate = None
+        lost = float(flow_el.get('lostPackets'))
+        #print "rxBytes: %s; txPackets: %s; rxPackets: %s; lostPackets: %s" % (flow_el.get('rxBytes'), txPackets, rxPackets, lost)
+        if rxPackets == 0:
+            self.packetLossRatio = None
+        else:
+            self.packetLossRatio = (lost / (rxPackets + lost))
+
+        interrupt_hist_elem = flow_el.find("flowInterruptionsHistogram")
+        if interrupt_hist_elem is None:
+            self.flowInterruptionsHistogram = None
+        else:
+            self.flowInterruptionsHistogram = Histogram(interrupt_hist_elem)
+
+
+class ProbeFlowStats(object):
+    __slots__ = ['probeId', 'packets', 'bytes', 'delayFromFirstProbe']
+
+class Simulation(object):
+    def __init__(self, simulation_el):
+        self.flows = []
+        FlowClassifier_el, = simulation_el.findall("Ipv4FlowClassifier")
+        flow_map = {}
+        for flow_el in simulation_el.findall("FlowStats/Flow"):
+            flow = Flow(flow_el)
+            flow_map[flow.flowId] = flow
+            self.flows.append(flow)
+        for flow_cls in FlowClassifier_el.findall("Flow"):
+            flowId = int(flow_cls.get('flowId'))
+            flow_map[flowId].fiveTuple = FiveTuple(flow_cls)
+
+        for probe_elem in simulation_el.findall("FlowProbes/FlowProbe"):
+            probeId = int(probe_elem.get('index'))
+            for stats in probe_elem.findall("FlowStats"):
+                flowId = int(stats.get('flowId'))
+                s = ProbeFlowStats()
+                s.packets = int(stats.get('packets'))
+                s.bytes = long(stats.get('bytes'))
+                s.probeId = probeId
+                if s.packets > 0:
+                    s.delayFromFirstProbe =  parse_time_ns(stats.get('delayFromFirstProbeSum')) / float(s.packets)
+                else:
+                    s.delayFromFirstProbe = 0
+                flow_map[flowId].probe_stats_unsorted.append(s)
+
+
+def main(argv):
+    file_obj = open(argv[1])
+    print "Reading XML file ",
+ 
+    sys.stdout.flush()        
+    level = 0
+    sim_list = []
+    for event, elem in ElementTree.iterparse(file_obj, events=("start", "end")):
+        if event == "start":
+            level += 1
+        if event == "end":
+            level -= 1
+            if level == 0 and elem.tag == 'FlowMonitor':
+                sim = Simulation(elem)
+                sim_list.append(sim)
+                elem.clear() # won't need this any more
+                sys.stdout.write(".")
+                sys.stdout.flush()
+    print " done."
+
+
+    for sim in sim_list:
+        for flow in sim.flows:
+            t = flow.fiveTuple
+            proto = {6: 'TCP', 17: 'UDP'} [t.protocol]
+            print "FlowID: %i (%s %s/%s --> %s/%i)" % \
+                (flow.flowId, proto, t.sourceAddress, t.sourcePort, t.destinationAddress, t.destinationPort)
+            print "\tTX bitrate: %.2f kbit/s" % (flow.txBitrate*1e-3,)
+            print "\tRX bitrate: %.2f kbit/s" % (flow.rxBitrate*1e-3,)
+            print "\tMean Delay: %.2f ms" % (flow.delayMean*1e3,)
+            print "\tPacket Loss Ratio: %.2f %%" % (flow.packetLossRatio*100)
+
+
+if __name__ == '__main__':
+    main(sys.argv)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/flow-monitor/examples/wifi-olsr-flowmon.py	Fri Oct 22 17:18:49 2010 +0100
@@ -0,0 +1,171 @@
+# -*-  Mode: Python; -*-
+#  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
+# 
+#  Authors: Gustavo Carneiro <gjc@inescporto.pt>
+
+import sys
+import ns3
+
+DISTANCE = 100 # (m)
+NUM_NODES_SIDE = 3
+
+def main(argv):
+
+    cmd = ns3.CommandLine()
+
+    cmd.NumNodesSide = None
+    cmd.AddValue("NumNodesSide", "Grid side number of nodes (total number of nodes will be this number squared)")
+
+    cmd.Results = None
+    cmd.AddValue("Results", "Write XML results to file")
+
+    cmd.Plot = None
+    cmd.AddValue("Plot", "Plot the results using the matplotlib python module")
+
+    cmd.Parse(argv)
+
+    wifi = ns3.WifiHelper.Default()
+    wifiMac = ns3.NqosWifiMacHelper.Default()
+    wifiPhy = ns3.YansWifiPhyHelper.Default()
+    wifiChannel = ns3.YansWifiChannelHelper.Default()
+    wifiPhy.SetChannel(wifiChannel.Create())
+    ssid = ns3.Ssid("wifi-default")
+    wifi.SetRemoteStationManager("ns3::ArfWifiManager")
+    wifiMac.SetType ("ns3::AdhocWifiMac", "Ssid", ns3.SsidValue(ssid))
+
+    internet = ns3.InternetStackHelper()
+    list_routing = ns3.Ipv4ListRoutingHelper()
+    olsr_routing = ns3.OlsrHelper()
+    static_routing = ns3.Ipv4StaticRoutingHelper()
+    list_routing.Add(static_routing, 0)
+    list_routing.Add(olsr_routing, 100)
+    internet.SetRoutingHelper(list_routing)
+
+    ipv4Addresses = ns3.Ipv4AddressHelper()
+    ipv4Addresses.SetBase(ns3.Ipv4Address("10.0.0.0"), ns3.Ipv4Mask("255.255.255.0"))
+
+    port = 9   # Discard port(RFC 863)
+    onOffHelper = ns3.OnOffHelper("ns3::UdpSocketFactory",
+                                  ns3.Address(ns3.InetSocketAddress(ns3.Ipv4Address("10.0.0.1"), port)))
+    onOffHelper.SetAttribute("DataRate", ns3.DataRateValue(ns3.DataRate("100kbps")))
+    onOffHelper.SetAttribute("OnTime", ns3.RandomVariableValue(ns3.ConstantVariable(1)))
+    onOffHelper.SetAttribute("OffTime", ns3.RandomVariableValue(ns3.ConstantVariable(0)))
+
+    addresses = []
+    nodes = []
+
+    if cmd.NumNodesSide is None:
+        num_nodes_side = NUM_NODES_SIDE
+    else:
+        num_nodes_side = int(cmd.NumNodesSide)
+
+    for xi in range(num_nodes_side):
+        for yi in range(num_nodes_side):
+
+            node = ns3.Node()
+            nodes.append(node)
+
+            internet.Install(ns3.NodeContainer(node))
+
+            mobility = ns3.ConstantPositionMobilityModel()
+            mobility.SetPosition(ns3.Vector(xi*DISTANCE, yi*DISTANCE, 0))
+            node.AggregateObject(mobility)
+            
+            devices = wifi.Install(wifiPhy, wifiMac, node)
+            ipv4_interfaces = ipv4Addresses.Assign(devices)
+            addresses.append(ipv4_interfaces.GetAddress(0))
+
+    for i, node in enumerate(nodes):
+        destaddr = addresses[(len(addresses) - 1 - i) % len(addresses)]
+        #print i, destaddr
+        onOffHelper.SetAttribute("Remote", ns3.AddressValue(ns3.InetSocketAddress(destaddr, port)))
+        app = onOffHelper.Install(ns3.NodeContainer(node))
+        app.Start(ns3.Seconds(ns3.UniformVariable(20, 30).GetValue()))
+            
+    #internet.EnablePcapAll("wifi-olsr")
+    flowmon_helper = ns3.FlowMonitorHelper()
+    #flowmon_helper.SetMonitorAttribute("StartTime", ns3.TimeValue(ns3.Seconds(31)))
+    monitor = flowmon_helper.InstallAll()
+    monitor.SetAttribute("DelayBinWidth", ns3.DoubleValue(0.001))
+    monitor.SetAttribute("JitterBinWidth", ns3.DoubleValue(0.001))
+    monitor.SetAttribute("PacketSizeBinWidth", ns3.DoubleValue(20))
+
+    ns3.Simulator.Stop(ns3.Seconds(44.0))
+    ns3.Simulator.Run()
+
+    def print_stats(os, st):
+        print >> os, "  Tx Bytes: ", st.txBytes
+        print >> os, "  Rx Bytes: ", st.rxBytes
+        print >> os, "  Tx Packets: ", st.txPackets
+        print >> os, "  Rx Packets: ", st.rxPackets
+        print >> os, "  Lost Packets: ", st.lostPackets
+        if st.rxPackets > 0:
+            print >> os, "  Mean{Delay}: ", (st.delaySum.GetSeconds() / st.rxPackets)
+	    print >> os, "  Mean{Jitter}: ", (st.jitterSum.GetSeconds() / (st.rxPackets-1))
+            print >> os, "  Mean{Hop Count}: ", float(st.timesForwarded) / st.rxPackets + 1
+
+        if 0:
+            print >> os, "Delay Histogram"
+            for i in range(st.delayHistogram.GetNBins () ):
+              print >> os, " ",i,"(", st.delayHistogram.GetBinStart (i), "-", \
+                  st.delayHistogram.GetBinEnd (i), "): ", st.delayHistogram.GetBinCount (i)
+            print >> os, "Jitter Histogram"
+            for i in range(st.jitterHistogram.GetNBins () ):
+              print >> os, " ",i,"(", st.jitterHistogram.GetBinStart (i), "-", \
+                  st.jitterHistogram.GetBinEnd (i), "): ", st.jitterHistogram.GetBinCount (i)
+            print >> os, "PacketSize Histogram"
+            for i in range(st.packetSizeHistogram.GetNBins () ):
+              print >> os, " ",i,"(", st.packetSizeHistogram.GetBinStart (i), "-", \
+                  st.packetSizeHistogram.GetBinEnd (i), "): ", st.packetSizeHistogram.GetBinCount (i)
+
+        for reason, drops in enumerate(st.packetsDropped):
+            print "  Packets dropped by reason %i: %i" % (reason, drops)
+        #for reason, drops in enumerate(st.bytesDropped):
+        #    print "Bytes dropped by reason %i: %i" % (reason, drops)
+
+    monitor.CheckForLostPackets()
+    classifier = flowmon_helper.GetClassifier()
+
+    if cmd.Results is None:
+        for flow_id, flow_stats in monitor.GetFlowStats():
+            t = classifier.FindFlow(flow_id)
+            proto = {6: 'TCP', 17: 'UDP'} [t.protocol]
+            print "FlowID: %i (%s %s/%s --> %s/%i)" % \
+                (flow_id, proto, t.sourceAddress, t.sourcePort, t.destinationAddress, t.destinationPort)
+            print_stats(sys.stdout, flow_stats)
+    else:
+        print monitor.SerializeToXmlFile(cmd.Results, True, True)
+
+
+    if cmd.Plot is not None:
+        import pylab
+        delays = []
+        for flow_id, flow_stats in monitor.GetFlowStats():
+            tupl = classifier.FindFlow(flow_id)
+            if tupl.protocol == 17 and tupl.sourcePort == 698:
+                continue
+            delays.append(flow_stats.delaySum.GetSeconds() / flow_stats.rxPackets)
+        pylab.hist(delays, 20)
+        pylab.xlabel("Delay (s)")
+        pylab.ylabel("Number of Flows")
+        pylab.show()
+
+    return 0
+
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))
+
--- a/src/contrib/flow-monitor/flow-classifier.cc	Fri Oct 22 14:59:56 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/* -*- 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)  
-{
-}
-
-FlowClassifier::~FlowClassifier ()
-{}
-
-FlowId
-FlowClassifier::GetNewFlowId ()
-{
-  return ++m_lastNewFlowId;
-}
-
-
-} // namespace ns3
-
--- a/src/contrib/flow-monitor/flow-classifier.h	Fri Oct 22 14:59:56 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/* -*- 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/simple-ref-count.h"
-#include <ostream>
-
-namespace ns3 {
-
-typedef uint32_t FlowId;
-typedef uint32_t FlowPacketId;
-
-/// provides a method to translate raw packet data into abstract
-/// ``flow identifier'' and ``packet identifier'' parameters.  These
-/// identifiers are unsigned 32-bit integers that uniquely identify a
-/// flow and a packet within that flow, respectively, for the whole
-/// simulation, regardless of the point in which the packet was
-/// captured.  These abstract identifiers are used in the
-/// communication between FlowProbe and FlowMonitor, and all collected
-/// statistics reference only those abstract identifiers in order to
-/// keep the core architecture generic and not tied down to any
-/// particular flow capture method or classification system.
-class FlowClassifier : public SimpleRefCount<FlowClassifier>
-{
-private:
-  FlowId m_lastNewFlowId;
-
-  FlowClassifier (FlowClassifier const &);
-  FlowClassifier& operator= (FlowClassifier const &);
-
-public:
-
-  FlowClassifier ();
-  virtual ~FlowClassifier ();
-
-  virtual void SerializeToXmlStream (std::ostream &os, int indent) const = 0;
-
-protected:
-  FlowId GetNewFlowId ();
-
-};
-
-
-} // namespace ns3
-
-#endif
-
--- a/src/contrib/flow-monitor/flow-monitor.cc	Fri Oct 22 14:59:56 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,487 +0,0 @@
-/* -*- 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> ())
-    .AddAttribute ("FlowInterruptionsBinWidth", ("The width used in the flowInterruptions histogram."),
-                   DoubleValue (0.250),
-                   MakeDoubleAccessor (&FlowMonitor::m_flowInterruptionsBinWidth),
-                   MakeDoubleChecker <double> ())
-    .AddAttribute ("FlowInterruptionsMinTime", ("The minimum inter-arrival time that is considered a flow interruption."),
-                   TimeValue (Seconds (0.5)),
-                   MakeTimeAccessor (&FlowMonitor::m_flowInterruptionsMinTime),
-                   MakeTimeChecker ())
-    ;
-  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);
-      ref.flowInterruptionsHistogram.SetDefaultBinWidth (m_flowInterruptionsBinWidth);
-      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;
-    }
-  else
-    {
-      // measure possible flow interruptions
-      Time interArrivalTime = now - stats.timeLastRxPacket;
-      if (interArrivalTime > m_flowInterruptionsMinTime)
-        {
-          stats.flowInterruptionsHistogram.AddValue (interArrivalTime.GetSeconds ());
-        }
-    }
-  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");
-          flowI->second.flowInterruptionsHistogram.SerializeToXmlStream (os, indent, "flowInterruptionsHistogram");
-        }
-      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
-
--- a/src/contrib/flow-monitor/flow-monitor.h	Fri Oct 22 14:59:56 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,247 +0,0 @@
-/* -*- 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 {
-
-/// \brief An object that monitors and reports back packet flows observed during a simulation
-///
-/// The FlowMonitor class is responsible forcoordinating efforts
-/// regarding probes, and collects end-to-end flowstatistics.
-class FlowMonitor : public Object
-{
-public:
-
-  /// \brief Structure that represents the measured metrics of an individual packet flow
-  struct FlowStats
-  {
-    /// Contains the absolute time when the first packet in the flow
-    /// was transmitted, i.e. the time when the flow transmission
-    /// starts
-    Time     timeFirstTxPacket;
-
-    /// Contains the absolute time when the first packet in the flow
-    /// was received by an end node, i.e. the time when the flow
-    /// reception starts
-    Time     timeFirstRxPacket;
-    
-    /// Contains the absolute time when the last packet in the flow
-    /// was transmitted, i.e. the time when the flow transmission
-    /// ends
-    Time     timeLastTxPacket;
-
-    /// Contains the absolute time when the last packet in the flow
-    /// was received, i.e. the time when the flow reception ends
-    Time     timeLastRxPacket;
-
-    /// Contains the sum of all end-to-end delays for all received
-    /// packets of the flow.
-    Time     delaySum; // delayCount == rxPackets
-
-    /// Contains the sum of all end-to-end delay jitter (delay
-    /// variation) values for all received packets of the flow.  Here
-    /// we define _jitter_ of a packet as the delay variation
-    /// relatively to the last packet of the stream,
-    /// i.e. \f$Jitter\left\{P_N\right\} = \left|Delay\left\{P_N\right\} - Delay\left\{P_{N-1}\right\}\right|\f$.
-    /// This definition is in accordance with the Type-P-One-way-ipdv
-    /// as defined in IETF RFC 3393.
-    Time     jitterSum; // jitterCount == rxPackets - 1
-
-    Time     lastDelay;
-
-    /// Total number of transmitted bytes for the flow
-    uint64_t txBytes;
-    /// Total number of received bytes for the flow
-    uint64_t rxBytes;
-    /// Total number of transmitted packets for the flow
-    uint32_t txPackets;
-    /// Total number of received packets for the flow
-    uint32_t rxPackets;
-
-    /// Total number of packets that are assumed to be lost,
-    /// i.e. those that were transmitted but have not been reportedly
-    /// received or forwarded for a long time.  By default, packets
-    /// missing for a period of over 10 seconds are assumed to be
-    /// lost, although this value can be easily configured in runtime
-    uint32_t lostPackets;
-
-    /// Contains the number of times a packet has been reportedly
-    /// forwarded, summed for all received packets in the flow
-    uint32_t timesForwarded;
-
-    /// Histogram of the packet delays
-    Histogram delayHistogram;
-    /// Histogram of the packet jitters
-    Histogram jitterHistogram;
-    /// Histogram of the packet sizes
-    Histogram packetSizeHistogram;
-
-    /// This attribute also tracks the number of lost packets and
-    /// bytes, but discriminates the losses by a _reason code_.  This
-    /// reason code is usually an enumeration defined by the concrete
-    /// FlowProbe class, and for each reason code there may be a
-    /// vector entry indexed by that code and whose value is the
-    /// number of packets or bytes lost due to this reason.  For
-    /// instance, in the Ipv4FlowProbe case the following reasons are
-    /// currently defined: DROP_NO_ROUTE (no IPv4 route found for a
-    /// packet), DROP_TTL_EXPIRE (a packet was dropped due to an IPv4
-    /// TTL field decremented and reaching zero), and
-    /// DROP_BAD_CHECKSUM (a packet had bad IPv4 header checksum and
-    /// had to be dropped).
-    std::vector<uint32_t> packetsDropped; // packetsDropped[reasonCode] => number of dropped packets
-
-    /// This attribute also tracks the number of lost bytes.  See also
-    /// comment in attribute packetsDropped.
-    std::vector<uint64_t> bytesDropped; // bytesDropped[reasonCode] => number of dropped bytes
-    Histogram flowInterruptionsHistogram; // histogram of durations of flow interruptions
-  };
-
-  // --- basic methods ---
-  static TypeId GetTypeId ();
-  TypeId GetInstanceTypeId () const;
-  FlowMonitor ();
-
-  /// Set the FlowClassifier to be used by the flow monitor.
-  void SetFlowClassifier (Ptr<FlowClassifier> classifier);
-  
-  /// Set the time, counting from the current time, from which to start monitoring flows
-  void Start (const Time &time);
-  /// Set the time, counting from the current time, from which to stop monitoring flows
-  void Stop (const Time &time);
-  /// Begin monitoring flows *right now*
-  void StartRightNow ();
-  /// End monitoring flows *right now*
-  void StopRightNow ();
-
-  // --- methods to be used by the FlowMonitorProbe's only ---
-  /// Register a new FlowProbe that will begin monitoring and report
-  /// events to this monitor.  This method is normally only used by
-  /// FlowProbe implementations.
-  void AddProbe (Ptr<FlowProbe> probe);
-
-  /// FlowProbe implementations are supposed to call this method to
-  /// report that a new packet was transmitted (but keep in mind the
-  /// distinction between a new packet entering the system and a
-  /// packet that is already known and is only being forwarded).
-  void ReportFirstTx (Ptr<FlowProbe> probe, FlowId flowId, FlowPacketId packetId, uint32_t packetSize);
-  /// FlowProbe implementations are supposed to call this method to
-  /// report that a known packet is being forwarded.
-  void ReportForwarding (Ptr<FlowProbe> probe, FlowId flowId, FlowPacketId packetId, uint32_t packetSize);
-  /// FlowProbe implementations are supposed to call this method to
-  /// report that a known packet is being received.
-  void ReportLastRx (Ptr<FlowProbe> probe, FlowId flowId, FlowPacketId packetId, uint32_t packetSize);
-  /// FlowProbe implementations are supposed to call this method to
-  /// report that a known packet is being dropped due to some reason.
-  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 ();
-
-  /// Check right now for packets that appear to be lost, considering
-  /// packets as lost if not seen in the network for a time larger
-  /// than maxDelay
-  void CheckForLostPackets (Time maxDelay);  
-
-  // --- methods to get the results ---
-  /// Retrieve all collected the flow statistics.  Note, if the
-  /// FlowMonitor has not stopped monitoring yet, you should call
-  /// CheckForLostPackets() to make sure all possibly lost packets are
-  /// accounted for.
-  std::map<FlowId, FlowStats> GetFlowStats () const;
-
-  /// Get a list of all FlowProbe's associated with this FlowMonitor
-  std::vector< Ptr<FlowProbe> > GetAllProbes () const;
-
-  /// Serializes the results to an std::ostream in XML format
-  /// \param os the output stream
-  /// \param indent number of spaces to use as base indentation level
-  /// \param enableHistograms if true, include also the histograms in the output
-  /// \param enableProbes if true, include also the per-probe/flow pair statistics in the output
-  void SerializeToXmlStream (std::ostream &os, int indent, bool enableHistograms, bool enableProbes);
-  /// Same as SerializeToXmlStream, but returns the output as a std::string
-  /// \param indent number of spaces to use as base indentation level
-  /// \param enableHistograms if true, include also the histograms in the output
-  /// \param enableProbes if true, include also the per-probe/flow pair statistics in the output
-  /// \return the XML output as string
-  std::string SerializeToXmlString (int indent, bool enableHistograms, bool enableProbes);
-  /// Same as SerializeToXmlStream, but writes to a file instead
-  /// \param fileName name or path of the output file that will be created
-  /// \param enableHistograms if true, include also the histograms in the output
-  /// \param enableProbes if true, include also the per-probe/flow pair statistics in the output
-  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;
-  double m_flowInterruptionsBinWidth;
-  Time m_flowInterruptionsMinTime;
-
-  FlowStats& GetStatsForFlow (FlowId flowId);
-  void PeriodicCheckForLostPackets ();
-};
-
-
-} // namespace ns3
-
-#endif
-
--- a/src/contrib/flow-monitor/flow-probe.cc	Fri Oct 22 14:59:56 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +0,0 @@
-/* -*- 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
-
-
--- a/src/contrib/flow-monitor/flow-probe.h	Fri Oct 22 14:59:56 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/* -*- 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/simple-ref-count.h"
-#include "ns3/flow-classifier.h"
-#include "ns3/nstime.h"
-
-namespace ns3 {
-
-class FlowMonitor;
-  
-/// The FlowProbe class is responsible for listening for packet events
-/// in a specific point of the simulated space, report those events to
-/// the global FlowMonitor, and collect its own flow statistics
-/// regarding only the packets that pass through that probe.
-class FlowProbe : public SimpleRefCount<FlowProbe>
-{
-private:
-  FlowProbe (FlowProbe const &);
-  FlowProbe& operator= (FlowProbe const &);
-  
-protected:
-  
-  FlowProbe (Ptr<FlowMonitor> flowMonitor);
-  
-public:
-  virtual ~FlowProbe ();
-
-  struct FlowStats
-  {
-    FlowStats () : delayFromFirstProbeSum (Seconds (0)), bytes (0), packets (0) {}
-
-    /// packetsDropped[reasonCode] => number of dropped packets
-    std::vector<uint32_t> packetsDropped;
-    /// bytesDropped[reasonCode] => number of dropped bytes
-    std::vector<uint64_t> bytesDropped;
-    /// divide by 'Scalar (packets)' to get the average delay from the
-    /// first (entry) probe up to this one (partial delay)
-    Time delayFromFirstProbeSum;
-    /// Number of bytes seen of this flow
-    uint64_t bytes;
-    /// Number of packets seen of this flow
-    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);
-
-  /// Get the partial flow statistics stored in this probe.  With this
-  /// information you can, for example, find out what is the delay
-  /// from the first probe to this one.
-  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
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/flow-monitor/helper/flow-monitor-helper.cc	Fri Oct 22 17:18:49 2010 +0100
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/flow-monitor/helper/flow-monitor-helper.h	Fri Oct 22 17:18:49 2010 +0100
@@ -0,0 +1,69 @@
+// -*- 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 "ns3/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;  
+
+/// \brief Helper to enable IPv4 flow monitoring on a set of Nodes
+class FlowMonitorHelper
+{
+public:
+  /// \brief Construct a FlowMonitorHelper class which makes it easier to 
+  /// configure and use the FlowMonitor
+  FlowMonitorHelper ();
+  
+  /// \brief Set an attribute for the to-be-created FlowMonitor object
+  void SetMonitorAttribute (std::string n1, const AttributeValue &v1);
+
+  /// \brief Enable flow monitoring on a set of nodes
+  /// \param nodes A NodeContainer holding the set of nodes to work with.
+  Ptr<FlowMonitor> Install (NodeContainer nodes);
+  /// \brief Enable flow monitoring on a single node
+  /// \param node A Ptr<Node> to the node on which to enable flow monitoring.
+  Ptr<FlowMonitor> Install (Ptr<Node> node);
+  /// \brief Enable flow monitoring on all nodes
+  Ptr<FlowMonitor> InstallAll ();
+
+  /// \brief Retrieve the FlowMonitor object created by the Install* methods
+  Ptr<FlowMonitor> GetMonitor ();
+
+  /// \brief Retrieve the FlowClassifier object created by the Install* methods
+  Ptr<FlowClassifier> GetClassifier ();
+  
+private:
+  ObjectFactory m_monitorFactory;
+  Ptr<FlowMonitor> m_flowMonitor;
+  Ptr<FlowClassifier> m_flowClassifier;
+};
+
+} // namespace ns3
+
+
+#endif /* FLOW_MONITOR_HELPER_H */
--- a/src/contrib/flow-monitor/histogram.cc	Fri Oct 22 14:59:56 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,214 +0,0 @@
-/* -*- 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 = (uint32_t)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
-
-
-#include "ns3/test.h"
-
-namespace ns3 {
-
-class HistogramTestCase : public ns3::TestCase {
-private:
-public:
-  HistogramTestCase ();
-  virtual bool DoRun (void);
-
-
-};
-
-HistogramTestCase::HistogramTestCase ()
-  : ns3::TestCase ("Histogram")
-{}
-
-
-bool 
-HistogramTestCase::DoRun (void)
-{
-  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_EXPECT_MSG_EQ_TOL (h0.GetBinWidth (0),  3.5, 1e-6, "");
-    NS_TEST_EXPECT_MSG_EQ (h0.GetNBins (),  2, "");
-    NS_TEST_EXPECT_MSG_EQ_TOL (h0.GetBinStart (1),  3.5, 1e-6, "");
-    NS_TEST_EXPECT_MSG_EQ (h0.GetBinCount (0),  10, "");
-    NS_TEST_EXPECT_MSG_EQ (h0.GetBinCount (1),  5, "");
-  }
-  
-  {
-    // Testing bin expansion
-    h0.AddValue (74.3);
-    NS_TEST_EXPECT_MSG_EQ (h0.GetNBins (), 22, "");
-    NS_TEST_EXPECT_MSG_EQ (h0.GetBinCount (21), 1, "");
-  }
- 
-  return false;
-}
-
-static class HistogramTestSuite : public TestSuite
-{
-public:
-  HistogramTestSuite ()
-    : TestSuite ("histogram", UNIT) 
-  {
-    AddTestCase (new HistogramTestCase ());
-  }
-} g_HistogramTestSuite;
-
-} // namespace
-
-
--- a/src/contrib/flow-monitor/histogram.h	Fri Oct 22 14:59:56 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/* -*- 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
-
--- a/src/contrib/flow-monitor/ipv4-flow-classifier.cc	Fri Oct 22 14:59:56 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,203 +0,0 @@
-/* -*- 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
-
--- a/src/contrib/flow-monitor/ipv4-flow-classifier.h	Fri Oct 22 14:59:56 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/* -*- 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;
-
-/// Classifies packets by looking at their IP and TCP/UDP headers.
-/// From these packet headers, a tuple (source-ip, destination-ip,
-/// protocol, source-port, destination-port) is created, and a unique
-/// flow identifier is assigned for each different tuple combination
-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
-
--- a/src/contrib/flow-monitor/ipv4-flow-probe.cc	Fri Oct 22 14:59:56 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,341 +0,0 @@
-/* -*- 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"
-#include "ns3/config.h"
-#include "ns3/flow-id-tag.h"
-
-namespace ns3 {
-
-using namespace std;
-
-NS_LOG_COMPONENT_DEFINE ("Ipv4FlowProbe");
-
-            //////////////////////////////////////
-            // Ipv4FlowProbeTag class implementation //
-            //////////////////////////////////////
-
-class Ipv4FlowProbeTag : public Tag
-{
-public:
-  static TypeId GetTypeId (void);
-  virtual TypeId GetInstanceTypeId (void) const;
-  virtual uint32_t GetSerializedSize (void) const;
-  virtual void Serialize (TagBuffer buf) const;
-  virtual void Deserialize (TagBuffer buf);
-  virtual void Print (std::ostream &os) const;
-  Ipv4FlowProbeTag ();
-  Ipv4FlowProbeTag (uint32_t flowId, uint32_t packetId, uint32_t packetSize);
-  void SetFlowId (uint32_t flowId);
-  void SetPacketId (uint32_t packetId);
-  void SetPacketSize (uint32_t packetSize);
-  uint32_t GetFlowId (void) const;
-  uint32_t GetPacketId (void) const;
-  uint32_t GetPacketSize (void) const;
-private:
-  uint32_t m_flowId;
-  uint32_t m_packetId;
-  uint32_t m_packetSize;
-  
-};
-
-TypeId 
-Ipv4FlowProbeTag::GetTypeId (void)
-{
-  static TypeId tid = TypeId ("ns3::Ipv4FlowProbeTag")
-    .SetParent<Tag> ()
-    .AddConstructor<Ipv4FlowProbeTag> ()
-    ;
-  return tid;
-}
-TypeId 
-Ipv4FlowProbeTag::GetInstanceTypeId (void) const
-{
-  return GetTypeId ();
-}
-uint32_t 
-Ipv4FlowProbeTag::GetSerializedSize (void) const
-{
-  return 4 + 4 + 4;
-}
-void 
-Ipv4FlowProbeTag::Serialize (TagBuffer buf) const
-{
-  buf.WriteU32 (m_flowId);
-  buf.WriteU32 (m_packetId);
-  buf.WriteU32 (m_packetSize);
-}
-void 
-Ipv4FlowProbeTag::Deserialize (TagBuffer buf)
-{
-  m_flowId = buf.ReadU32 ();
-  m_packetId = buf.ReadU32 ();
-  m_packetSize = buf.ReadU32 ();
-}
-void 
-Ipv4FlowProbeTag::Print (std::ostream &os) const
-{
-  os << "FlowId=" << m_flowId;
-  os << "PacketId=" << m_packetId;
-  os << "PacketSize=" << m_packetSize;
-}
-Ipv4FlowProbeTag::Ipv4FlowProbeTag ()
-  : Tag () 
-{}
-
-Ipv4FlowProbeTag::Ipv4FlowProbeTag (uint32_t flowId, uint32_t packetId, uint32_t packetSize)
-  : Tag (), m_flowId (flowId), m_packetId (packetId), m_packetSize (packetSize)
-{}
-
-void
-Ipv4FlowProbeTag::SetFlowId (uint32_t id)
-{
-  m_flowId = id;
-}
-void
-Ipv4FlowProbeTag::SetPacketId (uint32_t id)
-{
-  m_packetId = id;
-}
-void
-Ipv4FlowProbeTag::SetPacketSize (uint32_t size)
-{
-  m_packetSize = size;
-}
-uint32_t
-Ipv4FlowProbeTag::GetFlowId (void) const
-{
-  return m_flowId;
-}  
-uint32_t
-Ipv4FlowProbeTag::GetPacketId (void) const
-{
-  return m_packetId;
-} 
-uint32_t
-Ipv4FlowProbeTag::GetPacketSize (void) const
-{
-  return m_packetSize;
-} 
-
-            ////////////////////////////////////////
-            // Ipv4FlowProbe class implementation //
-            ////////////////////////////////////////
-
-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");
-    }
-
-  // code copied from point-to-point-helper.cc
-  std::ostringstream oss;
-  oss << "/NodeList/" << node->GetId () << "/DeviceList/*/TxQueue/Drop";
-  Config::ConnectWithoutContext (oss.str (), MakeCallback (&Ipv4FlowProbe::QueueDropLogger, Ptr<Ipv4FlowProbe> (this)));
-}
-
-Ipv4FlowProbe::~Ipv4FlowProbe ()
-{
-}
-
-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);
-
-      // tag the packet with the flow id and packet id, so that the packet can be identified even
-      // when Ipv4Header is not accessible at some non-IPv4 protocol layer
-      Ipv4FlowProbeTag fTag (flowId, packetId, size);
-      ipPayload->AddPacketTag (fTag);
-    }
-}
-
-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))
-    {
-      // remove the tags that are added by Ipv4FlowProbe::SendOutgoingLogger ()
-      Ipv4FlowProbeTag fTag;
-
-      // ConstCast: see http://www.nsnam.org/bugzilla/show_bug.cgi?id=904
-      ConstCast<Packet> (ipPayload)->RemovePacketTag (fTag);
-
-      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, Ptr<Ipv4> ipv4, 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))
-    {
-      // remove the tags that are added by Ipv4FlowProbe::SendOutgoingLogger ()
-      Ipv4FlowProbeTag fTag;
-
-      // ConstCast: see http://www.nsnam.org/bugzilla/show_bug.cgi?id=904
-      ConstCast<Packet> (ipPayload)->RemovePacketTag (fTag);
-
-      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;
-        case Ipv4L3Protocol::DROP_INTERFACE_DOWN:
-          myReason = DROP_INTERFACE_DOWN;
-          NS_LOG_DEBUG ("DROP_INTERFACE_DOWN");
-          break;
-        case Ipv4L3Protocol::DROP_ROUTE_ERROR:
-          myReason = DROP_ROUTE_ERROR;
-          NS_LOG_DEBUG ("DROP_ROUTE_ERROR");
-          break;
-
-        default:
-          myReason = DROP_INVALID_REASON;
-          NS_FATAL_ERROR ("Unexpected drop reason code " << reason);
-        }
-
-      m_flowMonitor->ReportDrop (this, flowId, packetId, size, myReason);
-    }
-}
-
-void 
-Ipv4FlowProbe::QueueDropLogger (Ptr<const Packet> ipPayload)
-{
-  // remove the tags that are added by Ipv4FlowProbe::SendOutgoingLogger ()
-  Ipv4FlowProbeTag fTag;
-
-  // ConstCast: see http://www.nsnam.org/bugzilla/show_bug.cgi?id=904
-  bool tagFound;
-  tagFound = ConstCast<Packet> (ipPayload)->RemovePacketTag (fTag);
-  NS_ASSERT_MSG (tagFound, "FlowProbeTag is missing");
-  
-  FlowId flowId = fTag.GetFlowId ();
-  FlowPacketId packetId = fTag.GetPacketId ();
-  uint32_t size = fTag.GetPacketSize ();
-
-  NS_LOG_DEBUG ("Drop ("<<this<<", "<<flowId<<", "<<packetId<<", "<<size<<", " << DROP_QUEUE 
-                << "); ");
-
-  m_flowMonitor->ReportDrop (this, flowId, packetId, size, DROP_QUEUE);
-}
-
-} // namespace ns3
-
-
--- a/src/contrib/flow-monitor/ipv4-flow-probe.h	Fri Oct 22 14:59:56 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-/* -*- 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;
-
-/// \brief Class that monitors flows at the IPv4 layer of a Node
-///
-/// For each node in the simulation, one instance of the class
-/// Ipv4FlowProbe is created to monitor that node.  Ipv4FlowProbe
-/// accomplishes this by connecting callbacks to trace sources in the
-/// Ipv4L3Protocol interface of the node.
-class Ipv4FlowProbe : public FlowProbe
-{
-  
-public:
-  Ipv4FlowProbe (Ptr<FlowMonitor> monitor, Ptr<Ipv4FlowClassifier> classifier, Ptr<Node> node);
-  virtual ~Ipv4FlowProbe ();
-
-  /// \brief enumeration of possible reasons why a packet may be dropped
-  enum DropReason 
-    {
-      /// Packet dropped due to missing route to the destination
-      DROP_NO_ROUTE = 0,
-
-      /// Packet dropped due to TTL decremented to zero during IPv4 forwarding
-      DROP_TTL_EXPIRE,      
-
-      /// Packet dropped due to invalid checksum in the IPv4 header
-      DROP_BAD_CHECKSUM,
-
-      /// Packet dropped due to queue overflow.  Note: only works for
-      /// NetDevices that provide a TxQueue attribute of type Queue
-      /// with a Drop trace source.  It currently works with Csma and
-      /// PointToPoint devices, but not with WiFi or WiMax.
-      DROP_QUEUE,
-
-      DROP_INTERFACE_DOWN, /**< Interface is down so can not send packet */
-      DROP_ROUTE_ERROR, /**< Route error */
-      
-      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, Ptr<Ipv4> ipv4, uint32_t ifIndex);
-  void QueueDropLogger (Ptr<const Packet> ipPayload);
-
-  Ptr<Ipv4FlowClassifier> m_classifier;
-};
-
-
-} // namespace ns3
-
-#endif
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/flow-monitor/model/flow-classifier.cc	Fri Oct 22 17:18:49 2010 +0100
@@ -0,0 +1,42 @@
+/* -*- 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)  
+{
+}
+
+FlowClassifier::~FlowClassifier ()
+{}
+
+FlowId
+FlowClassifier::GetNewFlowId ()
+{
+  return ++m_lastNewFlowId;
+}
+
+
+} // namespace ns3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/flow-monitor/model/flow-classifier.h	Fri Oct 22 17:18:49 2010 +0100
@@ -0,0 +1,66 @@
+/* -*- 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/simple-ref-count.h"
+#include <ostream>
+
+namespace ns3 {
+
+typedef uint32_t FlowId;
+typedef uint32_t FlowPacketId;
+
+/// provides a method to translate raw packet data into abstract
+/// ``flow identifier'' and ``packet identifier'' parameters.  These
+/// identifiers are unsigned 32-bit integers that uniquely identify a
+/// flow and a packet within that flow, respectively, for the whole
+/// simulation, regardless of the point in which the packet was
+/// captured.  These abstract identifiers are used in the
+/// communication between FlowProbe and FlowMonitor, and all collected
+/// statistics reference only those abstract identifiers in order to
+/// keep the core architecture generic and not tied down to any
+/// particular flow capture method or classification system.
+class FlowClassifier : public SimpleRefCount<FlowClassifier>
+{
+private:
+  FlowId m_lastNewFlowId;
+
+  FlowClassifier (FlowClassifier const &);
+  FlowClassifier& operator= (FlowClassifier const &);
+
+public:
+
+  FlowClassifier ();
+  virtual ~FlowClassifier ();
+
+  virtual void SerializeToXmlStream (std::ostream &os, int indent) const = 0;
+
+protected:
+  FlowId GetNewFlowId ();
+
+};
+
+
+} // namespace ns3
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/flow-monitor/model/flow-monitor.cc	Fri Oct 22 17:18:49 2010 +0100
@@ -0,0 +1,487 @@
+/* -*- 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> ())
+    .AddAttribute ("FlowInterruptionsBinWidth", ("The width used in the flowInterruptions histogram."),
+                   DoubleValue (0.250),
+                   MakeDoubleAccessor (&FlowMonitor::m_flowInterruptionsBinWidth),
+                   MakeDoubleChecker <double> ())
+    .AddAttribute ("FlowInterruptionsMinTime", ("The minimum inter-arrival time that is considered a flow interruption."),
+                   TimeValue (Seconds (0.5)),
+                   MakeTimeAccessor (&FlowMonitor::m_flowInterruptionsMinTime),
+                   MakeTimeChecker ())
+    ;
+  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);
+      ref.flowInterruptionsHistogram.SetDefaultBinWidth (m_flowInterruptionsBinWidth);
+      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;
+    }
+  else
+    {
+      // measure possible flow interruptions
+      Time interArrivalTime = now - stats.timeLastRxPacket;
+      if (interArrivalTime > m_flowInterruptionsMinTime)
+        {
+          stats.flowInterruptionsHistogram.AddValue (interArrivalTime.GetSeconds ());
+        }
+    }
+  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");
+          flowI->second.flowInterruptionsHistogram.SerializeToXmlStream (os, indent, "flowInterruptionsHistogram");
+        }
+      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
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/flow-monitor/model/flow-monitor.h	Fri Oct 22 17:18:49 2010 +0100
@@ -0,0 +1,247 @@
+/* -*- 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 {
+
+/// \brief An object that monitors and reports back packet flows observed during a simulation
+///
+/// The FlowMonitor class is responsible forcoordinating efforts
+/// regarding probes, and collects end-to-end flowstatistics.
+class FlowMonitor : public Object
+{
+public:
+
+  /// \brief Structure that represents the measured metrics of an individual packet flow
+  struct FlowStats
+  {
+    /// Contains the absolute time when the first packet in the flow
+    /// was transmitted, i.e. the time when the flow transmission
+    /// starts
+    Time     timeFirstTxPacket;
+
+    /// Contains the absolute time when the first packet in the flow
+    /// was received by an end node, i.e. the time when the flow
+    /// reception starts
+    Time     timeFirstRxPacket;
+    
+    /// Contains the absolute time when the last packet in the flow
+    /// was transmitted, i.e. the time when the flow transmission
+    /// ends
+    Time     timeLastTxPacket;
+
+    /// Contains the absolute time when the last packet in the flow
+    /// was received, i.e. the time when the flow reception ends
+    Time     timeLastRxPacket;
+
+    /// Contains the sum of all end-to-end delays for all received
+    /// packets of the flow.
+    Time     delaySum; // delayCount == rxPackets
+
+    /// Contains the sum of all end-to-end delay jitter (delay
+    /// variation) values for all received packets of the flow.  Here
+    /// we define _jitter_ of a packet as the delay variation
+    /// relatively to the last packet of the stream,
+    /// i.e. \f$Jitter\left\{P_N\right\} = \left|Delay\left\{P_N\right\} - Delay\left\{P_{N-1}\right\}\right|\f$.
+    /// This definition is in accordance with the Type-P-One-way-ipdv
+    /// as defined in IETF RFC 3393.
+    Time     jitterSum; // jitterCount == rxPackets - 1
+
+    Time     lastDelay;
+
+    /// Total number of transmitted bytes for the flow
+    uint64_t txBytes;
+    /// Total number of received bytes for the flow
+    uint64_t rxBytes;
+    /// Total number of transmitted packets for the flow
+    uint32_t txPackets;
+    /// Total number of received packets for the flow
+    uint32_t rxPackets;
+
+    /// Total number of packets that are assumed to be lost,
+    /// i.e. those that were transmitted but have not been reportedly
+    /// received or forwarded for a long time.  By default, packets
+    /// missing for a period of over 10 seconds are assumed to be
+    /// lost, although this value can be easily configured in runtime
+    uint32_t lostPackets;
+
+    /// Contains the number of times a packet has been reportedly
+    /// forwarded, summed for all received packets in the flow
+    uint32_t timesForwarded;
+
+    /// Histogram of the packet delays
+    Histogram delayHistogram;
+    /// Histogram of the packet jitters
+    Histogram jitterHistogram;
+    /// Histogram of the packet sizes
+    Histogram packetSizeHistogram;
+
+    /// This attribute also tracks the number of lost packets and
+    /// bytes, but discriminates the losses by a _reason code_.  This
+    /// reason code is usually an enumeration defined by the concrete
+    /// FlowProbe class, and for each reason code there may be a
+    /// vector entry indexed by that code and whose value is the
+    /// number of packets or bytes lost due to this reason.  For
+    /// instance, in the Ipv4FlowProbe case the following reasons are
+    /// currently defined: DROP_NO_ROUTE (no IPv4 route found for a
+    /// packet), DROP_TTL_EXPIRE (a packet was dropped due to an IPv4
+    /// TTL field decremented and reaching zero), and
+    /// DROP_BAD_CHECKSUM (a packet had bad IPv4 header checksum and
+    /// had to be dropped).
+    std::vector<uint32_t> packetsDropped; // packetsDropped[reasonCode] => number of dropped packets
+
+    /// This attribute also tracks the number of lost bytes.  See also
+    /// comment in attribute packetsDropped.
+    std::vector<uint64_t> bytesDropped; // bytesDropped[reasonCode] => number of dropped bytes
+    Histogram flowInterruptionsHistogram; // histogram of durations of flow interruptions
+  };
+
+  // --- basic methods ---
+  static TypeId GetTypeId ();
+  TypeId GetInstanceTypeId () const;
+  FlowMonitor ();
+
+  /// Set the FlowClassifier to be used by the flow monitor.
+  void SetFlowClassifier (Ptr<FlowClassifier> classifier);
+  
+  /// Set the time, counting from the current time, from which to start monitoring flows
+  void Start (const Time &time);
+  /// Set the time, counting from the current time, from which to stop monitoring flows
+  void Stop (const Time &time);
+  /// Begin monitoring flows *right now*
+  void StartRightNow ();
+  /// End monitoring flows *right now*
+  void StopRightNow ();
+
+  // --- methods to be used by the FlowMonitorProbe's only ---
+  /// Register a new FlowProbe that will begin monitoring and report
+  /// events to this monitor.  This method is normally only used by
+  /// FlowProbe implementations.
+  void AddProbe (Ptr<FlowProbe> probe);
+
+  /// FlowProbe implementations are supposed to call this method to
+  /// report that a new packet was transmitted (but keep in mind the
+  /// distinction between a new packet entering the system and a
+  /// packet that is already known and is only being forwarded).
+  void ReportFirstTx (Ptr<FlowProbe> probe, FlowId flowId, FlowPacketId packetId, uint32_t packetSize);
+  /// FlowProbe implementations are supposed to call this method to
+  /// report that a known packet is being forwarded.
+  void ReportForwarding (Ptr<FlowProbe> probe, FlowId flowId, FlowPacketId packetId, uint32_t packetSize);
+  /// FlowProbe implementations are supposed to call this method to
+  /// report that a known packet is being received.
+  void ReportLastRx (Ptr<FlowProbe> probe, FlowId flowId, FlowPacketId packetId, uint32_t packetSize);
+  /// FlowProbe implementations are supposed to call this method to
+  /// report that a known packet is being dropped due to some reason.
+  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 ();
+
+  /// Check right now for packets that appear to be lost, considering
+  /// packets as lost if not seen in the network for a time larger
+  /// than maxDelay
+  void CheckForLostPackets (Time maxDelay);  
+
+  // --- methods to get the results ---
+  /// Retrieve all collected the flow statistics.  Note, if the
+  /// FlowMonitor has not stopped monitoring yet, you should call
+  /// CheckForLostPackets() to make sure all possibly lost packets are
+  /// accounted for.
+  std::map<FlowId, FlowStats> GetFlowStats () const;
+
+  /// Get a list of all FlowProbe's associated with this FlowMonitor
+  std::vector< Ptr<FlowProbe> > GetAllProbes () const;
+
+  /// Serializes the results to an std::ostream in XML format
+  /// \param os the output stream
+  /// \param indent number of spaces to use as base indentation level
+  /// \param enableHistograms if true, include also the histograms in the output
+  /// \param enableProbes if true, include also the per-probe/flow pair statistics in the output
+  void SerializeToXmlStream (std::ostream &os, int indent, bool enableHistograms, bool enableProbes);
+  /// Same as SerializeToXmlStream, but returns the output as a std::string
+  /// \param indent number of spaces to use as base indentation level
+  /// \param enableHistograms if true, include also the histograms in the output
+  /// \param enableProbes if true, include also the per-probe/flow pair statistics in the output
+  /// \return the XML output as string
+  std::string SerializeToXmlString (int indent, bool enableHistograms, bool enableProbes);
+  /// Same as SerializeToXmlStream, but writes to a file instead
+  /// \param fileName name or path of the output file that will be created
+  /// \param enableHistograms if true, include also the histograms in the output
+  /// \param enableProbes if true, include also the per-probe/flow pair statistics in the output
+  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;
+  double m_flowInterruptionsBinWidth;
+  Time m_flowInterruptionsMinTime;
+
+  FlowStats& GetStatsForFlow (FlowId flowId);
+  void PeriodicCheckForLostPackets ();
+};
+
+
+} // namespace ns3
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/flow-monitor/model/flow-probe.cc	Fri Oct 22 17:18:49 2010 +0100
@@ -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
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/flow-monitor/model/flow-probe.h	Fri Oct 22 17:18:49 2010 +0100
@@ -0,0 +1,91 @@
+/* -*- 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/simple-ref-count.h"
+#include "ns3/flow-classifier.h"
+#include "ns3/nstime.h"
+
+namespace ns3 {
+
+class FlowMonitor;
+  
+/// The FlowProbe class is responsible for listening for packet events
+/// in a specific point of the simulated space, report those events to
+/// the global FlowMonitor, and collect its own flow statistics
+/// regarding only the packets that pass through that probe.
+class FlowProbe : public SimpleRefCount<FlowProbe>
+{
+private:
+  FlowProbe (FlowProbe const &);
+  FlowProbe& operator= (FlowProbe const &);
+  
+protected:
+  
+  FlowProbe (Ptr<FlowMonitor> flowMonitor);
+  
+public:
+  virtual ~FlowProbe ();
+
+  struct FlowStats
+  {
+    FlowStats () : delayFromFirstProbeSum (Seconds (0)), bytes (0), packets (0) {}
+
+    /// packetsDropped[reasonCode] => number of dropped packets
+    std::vector<uint32_t> packetsDropped;
+    /// bytesDropped[reasonCode] => number of dropped bytes
+    std::vector<uint64_t> bytesDropped;
+    /// divide by 'Scalar (packets)' to get the average delay from the
+    /// first (entry) probe up to this one (partial delay)
+    Time delayFromFirstProbeSum;
+    /// Number of bytes seen of this flow
+    uint64_t bytes;
+    /// Number of packets seen of this flow
+    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);
+
+  /// Get the partial flow statistics stored in this probe.  With this
+  /// information you can, for example, find out what is the delay
+  /// from the first probe to this one.
+  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
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/flow-monitor/model/histogram.cc	Fri Oct 22 17:18:49 2010 +0100
@@ -0,0 +1,214 @@
+/* -*- 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 = (uint32_t)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
+
+
+#include "ns3/test.h"
+
+namespace ns3 {
+
+class HistogramTestCase : public ns3::TestCase {
+private:
+public:
+  HistogramTestCase ();
+  virtual bool DoRun (void);
+
+
+};
+
+HistogramTestCase::HistogramTestCase ()
+  : ns3::TestCase ("Histogram")
+{}
+
+
+bool 
+HistogramTestCase::DoRun (void)
+{
+  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_EXPECT_MSG_EQ_TOL (h0.GetBinWidth (0),  3.5, 1e-6, "");
+    NS_TEST_EXPECT_MSG_EQ (h0.GetNBins (),  2, "");
+    NS_TEST_EXPECT_MSG_EQ_TOL (h0.GetBinStart (1),  3.5, 1e-6, "");
+    NS_TEST_EXPECT_MSG_EQ (h0.GetBinCount (0),  10, "");
+    NS_TEST_EXPECT_MSG_EQ (h0.GetBinCount (1),  5, "");
+  }
+  
+  {
+    // Testing bin expansion
+    h0.AddValue (74.3);
+    NS_TEST_EXPECT_MSG_EQ (h0.GetNBins (), 22, "");
+    NS_TEST_EXPECT_MSG_EQ (h0.GetBinCount (21), 1, "");
+  }
+ 
+  return false;
+}
+
+static class HistogramTestSuite : public TestSuite
+{
+public:
+  HistogramTestSuite ()
+    : TestSuite ("histogram", UNIT) 
+  {
+    AddTestCase (new HistogramTestCase ());
+  }
+} g_HistogramTestSuite;
+
+} // namespace
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/flow-monitor/model/histogram.h	Fri Oct 22 17:18:49 2010 +0100
@@ -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
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/flow-monitor/model/ipv4-flow-classifier.cc	Fri Oct 22 17:18:49 2010 +0100
@@ -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
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/flow-monitor/model/ipv4-flow-classifier.h	Fri Oct 22 17:18:49 2010 +0100
@@ -0,0 +1,78 @@
+/* -*- 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;
+
+/// Classifies packets by looking at their IP and TCP/UDP headers.
+/// From these packet headers, a tuple (source-ip, destination-ip,
+/// protocol, source-port, destination-port) is created, and a unique
+/// flow identifier is assigned for each different tuple combination
+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
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/flow-monitor/model/ipv4-flow-probe.cc	Fri Oct 22 17:18:49 2010 +0100
@@ -0,0 +1,341 @@
+/* -*- 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"
+#include "ns3/config.h"
+#include "ns3/flow-id-tag.h"
+
+namespace ns3 {
+
+using namespace std;
+
+NS_LOG_COMPONENT_DEFINE ("Ipv4FlowProbe");
+
+            //////////////////////////////////////
+            // Ipv4FlowProbeTag class implementation //
+            //////////////////////////////////////
+
+class Ipv4FlowProbeTag : public Tag
+{
+public:
+  static TypeId GetTypeId (void);
+  virtual TypeId GetInstanceTypeId (void) const;
+  virtual uint32_t GetSerializedSize (void) const;
+  virtual void Serialize (TagBuffer buf) const;
+  virtual void Deserialize (TagBuffer buf);
+  virtual void Print (std::ostream &os) const;
+  Ipv4FlowProbeTag ();
+  Ipv4FlowProbeTag (uint32_t flowId, uint32_t packetId, uint32_t packetSize);
+  void SetFlowId (uint32_t flowId);
+  void SetPacketId (uint32_t packetId);
+  void SetPacketSize (uint32_t packetSize);
+  uint32_t GetFlowId (void) const;
+  uint32_t GetPacketId (void) const;
+  uint32_t GetPacketSize (void) const;
+private:
+  uint32_t m_flowId;
+  uint32_t m_packetId;
+  uint32_t m_packetSize;
+  
+};
+
+TypeId 
+Ipv4FlowProbeTag::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::Ipv4FlowProbeTag")
+    .SetParent<Tag> ()
+    .AddConstructor<Ipv4FlowProbeTag> ()
+    ;
+  return tid;
+}
+TypeId 
+Ipv4FlowProbeTag::GetInstanceTypeId (void) const
+{
+  return GetTypeId ();
+}
+uint32_t 
+Ipv4FlowProbeTag::GetSerializedSize (void) const
+{
+  return 4 + 4 + 4;
+}
+void 
+Ipv4FlowProbeTag::Serialize (TagBuffer buf) const
+{
+  buf.WriteU32 (m_flowId);
+  buf.WriteU32 (m_packetId);
+  buf.WriteU32 (m_packetSize);
+}
+void 
+Ipv4FlowProbeTag::Deserialize (TagBuffer buf)
+{
+  m_flowId = buf.ReadU32 ();
+  m_packetId = buf.ReadU32 ();
+  m_packetSize = buf.ReadU32 ();
+}
+void 
+Ipv4FlowProbeTag::Print (std::ostream &os) const
+{
+  os << "FlowId=" << m_flowId;
+  os << "PacketId=" << m_packetId;
+  os << "PacketSize=" << m_packetSize;
+}
+Ipv4FlowProbeTag::Ipv4FlowProbeTag ()
+  : Tag () 
+{}
+
+Ipv4FlowProbeTag::Ipv4FlowProbeTag (uint32_t flowId, uint32_t packetId, uint32_t packetSize)
+  : Tag (), m_flowId (flowId), m_packetId (packetId), m_packetSize (packetSize)
+{}
+
+void
+Ipv4FlowProbeTag::SetFlowId (uint32_t id)
+{
+  m_flowId = id;
+}
+void
+Ipv4FlowProbeTag::SetPacketId (uint32_t id)
+{
+  m_packetId = id;
+}
+void
+Ipv4FlowProbeTag::SetPacketSize (uint32_t size)
+{
+  m_packetSize = size;
+}
+uint32_t
+Ipv4FlowProbeTag::GetFlowId (void) const
+{
+  return m_flowId;
+}  
+uint32_t
+Ipv4FlowProbeTag::GetPacketId (void) const
+{
+  return m_packetId;
+} 
+uint32_t
+Ipv4FlowProbeTag::GetPacketSize (void) const
+{
+  return m_packetSize;
+} 
+
+            ////////////////////////////////////////
+            // Ipv4FlowProbe class implementation //
+            ////////////////////////////////////////
+
+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");
+    }
+
+  // code copied from point-to-point-helper.cc
+  std::ostringstream oss;
+  oss << "/NodeList/" << node->GetId () << "/DeviceList/*/TxQueue/Drop";
+  Config::ConnectWithoutContext (oss.str (), MakeCallback (&Ipv4FlowProbe::QueueDropLogger, Ptr<Ipv4FlowProbe> (this)));
+}
+
+Ipv4FlowProbe::~Ipv4FlowProbe ()
+{
+}
+
+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);
+
+      // tag the packet with the flow id and packet id, so that the packet can be identified even
+      // when Ipv4Header is not accessible at some non-IPv4 protocol layer
+      Ipv4FlowProbeTag fTag (flowId, packetId, size);
+      ipPayload->AddPacketTag (fTag);
+    }
+}
+
+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))
+    {
+      // remove the tags that are added by Ipv4FlowProbe::SendOutgoingLogger ()
+      Ipv4FlowProbeTag fTag;
+
+      // ConstCast: see http://www.nsnam.org/bugzilla/show_bug.cgi?id=904
+      ConstCast<Packet> (ipPayload)->RemovePacketTag (fTag);
+
+      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, Ptr<Ipv4> ipv4, 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))
+    {
+      // remove the tags that are added by Ipv4FlowProbe::SendOutgoingLogger ()
+      Ipv4FlowProbeTag fTag;
+
+      // ConstCast: see http://www.nsnam.org/bugzilla/show_bug.cgi?id=904
+      ConstCast<Packet> (ipPayload)->RemovePacketTag (fTag);
+
+      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;
+        case Ipv4L3Protocol::DROP_INTERFACE_DOWN:
+          myReason = DROP_INTERFACE_DOWN;
+          NS_LOG_DEBUG ("DROP_INTERFACE_DOWN");
+          break;
+        case Ipv4L3Protocol::DROP_ROUTE_ERROR:
+          myReason = DROP_ROUTE_ERROR;
+          NS_LOG_DEBUG ("DROP_ROUTE_ERROR");
+          break;
+
+        default:
+          myReason = DROP_INVALID_REASON;
+          NS_FATAL_ERROR ("Unexpected drop reason code " << reason);
+        }
+
+      m_flowMonitor->ReportDrop (this, flowId, packetId, size, myReason);
+    }
+}
+
+void 
+Ipv4FlowProbe::QueueDropLogger (Ptr<const Packet> ipPayload)
+{
+  // remove the tags that are added by Ipv4FlowProbe::SendOutgoingLogger ()
+  Ipv4FlowProbeTag fTag;
+
+  // ConstCast: see http://www.nsnam.org/bugzilla/show_bug.cgi?id=904
+  bool tagFound;
+  tagFound = ConstCast<Packet> (ipPayload)->RemovePacketTag (fTag);
+  NS_ASSERT_MSG (tagFound, "FlowProbeTag is missing");
+  
+  FlowId flowId = fTag.GetFlowId ();
+  FlowPacketId packetId = fTag.GetPacketId ();
+  uint32_t size = fTag.GetPacketSize ();
+
+  NS_LOG_DEBUG ("Drop ("<<this<<", "<<flowId<<", "<<packetId<<", "<<size<<", " << DROP_QUEUE 
+                << "); ");
+
+  m_flowMonitor->ReportDrop (this, flowId, packetId, size, DROP_QUEUE);
+}
+
+} // namespace ns3
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/contrib/flow-monitor/model/ipv4-flow-probe.h	Fri Oct 22 17:18:49 2010 +0100
@@ -0,0 +1,86 @@
+/* -*- 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;
+
+/// \brief Class that monitors flows at the IPv4 layer of a Node
+///
+/// For each node in the simulation, one instance of the class
+/// Ipv4FlowProbe is created to monitor that node.  Ipv4FlowProbe
+/// accomplishes this by connecting callbacks to trace sources in the
+/// Ipv4L3Protocol interface of the node.
+class Ipv4FlowProbe : public FlowProbe
+{
+  
+public:
+  Ipv4FlowProbe (Ptr<FlowMonitor> monitor, Ptr<Ipv4FlowClassifier> classifier, Ptr<Node> node);
+  virtual ~Ipv4FlowProbe ();
+
+  /// \brief enumeration of possible reasons why a packet may be dropped
+  enum DropReason 
+    {
+      /// Packet dropped due to missing route to the destination
+      DROP_NO_ROUTE = 0,
+
+      /// Packet dropped due to TTL decremented to zero during IPv4 forwarding
+      DROP_TTL_EXPIRE,      
+
+      /// Packet dropped due to invalid checksum in the IPv4 header
+      DROP_BAD_CHECKSUM,
+
+      /// Packet dropped due to queue overflow.  Note: only works for
+      /// NetDevices that provide a TxQueue attribute of type Queue
+      /// with a Drop trace source.  It currently works with Csma and
+      /// PointToPoint devices, but not with WiFi or WiMax.
+      DROP_QUEUE,
+
+      DROP_INTERFACE_DOWN, /**< Interface is down so can not send packet */
+      DROP_ROUTE_ERROR, /**< Route error */
+      
+      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, Ptr<Ipv4> ipv4, uint32_t ifIndex);
+  void QueueDropLogger (Ptr<const Packet> ipPayload);
+
+  Ptr<Ipv4FlowClassifier> m_classifier;
+};
+
+
+} // namespace ns3
+
+#endif
+
--- a/src/contrib/flow-monitor/wscript	Fri Oct 22 14:59:56 2010 +0100
+++ b/src/contrib/flow-monitor/wscript	Fri Oct 22 17:18:49 2010 +0100
@@ -2,22 +2,24 @@
 
 def build(bld):
     obj = bld.create_ns3_module('flow-monitor', ['internet-stack'])
-    obj.source = [
+    obj.source = ["model/%s" % s for s in [
        'flow-monitor.cc',
        'flow-classifier.cc',
        'flow-probe.cc',
        'ipv4-flow-classifier.cc',
        'ipv4-flow-probe.cc',
        'histogram.cc',	
-        ]
+        ]]
+    obj.source.append("helper/flow-monitor-helper.cc")
+
     headers = bld.new_task_gen('ns3header')
     headers.module = 'flow-monitor'
-    headers.source = [
+    headers.source = ["model/%s" % s for s in [
        'flow-monitor.h',
        'flow-probe.h',
        'flow-classifier.h',
        'ipv4-flow-classifier.h',
        'ipv4-flow-probe.h',
        'histogram.h',
-        ]
-
+        ]]
+    headers.source.append("helper/flow-monitor-helper.h")
--- a/src/helper/flow-monitor-helper.cc	Fri Oct 22 14:59:56 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +0,0 @@
-// -*- 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
--- a/src/helper/flow-monitor-helper.h	Fri Oct 22 14:59:56 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-// -*- 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;  
-
-/// \brief Helper to enable IPv4 flow monitoring on a set of Nodes
-class FlowMonitorHelper
-{
-public:
-  /// \brief Construct a FlowMonitorHelper class which makes it easier to 
-  /// configure and use the FlowMonitor
-  FlowMonitorHelper ();
-  
-  /// \brief Set an attribute for the to-be-created FlowMonitor object
-  void SetMonitorAttribute (std::string n1, const AttributeValue &v1);
-
-  /// \brief Enable flow monitoring on a set of nodes
-  /// \param nodes A NodeContainer holding the set of nodes to work with.
-  Ptr<FlowMonitor> Install (NodeContainer nodes);
-  /// \brief Enable flow monitoring on a single node
-  /// \param node A Ptr<Node> to the node on which to enable flow monitoring.
-  Ptr<FlowMonitor> Install (Ptr<Node> node);
-  /// \brief Enable flow monitoring on all nodes
-  Ptr<FlowMonitor> InstallAll ();
-
-  /// \brief Retrieve the FlowMonitor object created by the Install* methods
-  Ptr<FlowMonitor> GetMonitor ();
-
-  /// \brief Retrieve the FlowClassifier object created by the Install* methods
-  Ptr<FlowClassifier> GetClassifier ();
-  
-private:
-  ObjectFactory m_monitorFactory;
-  Ptr<FlowMonitor> m_flowMonitor;
-  Ptr<FlowClassifier> m_flowClassifier;
-};
-
-} // namespace ns3
-
-
-#endif /* FLOW_MONITOR_HELPER_H */
--- a/src/helper/wscript	Fri Oct 22 14:59:56 2010 +0100
+++ b/src/helper/wscript	Fri Oct 22 17:18:49 2010 +0100
@@ -42,7 +42,6 @@
         'ipv6-list-routing-helper.cc',
         'ipv6-routing-helper.cc',
         'ping6-helper.cc',
-        'flow-monitor-helper.cc',
         'animation-interface.cc',
         'canvas-location.cc',
         'point-to-point-dumbbell-helper.cc',
@@ -100,7 +99,6 @@
         'ipv6-list-routing-helper.h',
         'ipv6-routing-helper.h',
         'ping6-helper.h',
-        'flow-monitor-helper.h',
         'animation-interface.h',
         'canvas-location.h',
         'point-to-point-dumbbell-helper.h',