flow-monitor: Keep track of the DSCP value of packets
authorStefano Avallone <stavallo@unina.it>
Wed, 08 Mar 2017 18:02:10 +0100
changeset 12745 8d6d77be85bc
parent 12744 f08e150547d0
child 12746 e0f75d385b61
flow-monitor: Keep track of the DSCP value of packets
CHANGES.html
examples/traffic-control/traffic-control.cc
src/flow-monitor/model/ipv4-flow-classifier.cc
src/flow-monitor/model/ipv4-flow-classifier.h
src/flow-monitor/model/ipv6-flow-classifier.cc
src/flow-monitor/model/ipv6-flow-classifier.h
--- a/CHANGES.html	Wed Mar 08 18:02:07 2017 +0100
+++ b/CHANGES.html	Wed Mar 08 18:02:10 2017 +0100
@@ -86,6 +86,10 @@
     optional and if not specified defaults to the previous behavior (Time::S).
 </li>
 <li><b>TxopTrace</b>: new trace source exported by EdcaTxopN.</li>
+<li>A <b>GetDscpCounts</b> method is added to <b>Ipv4FlowClassifier</b> and <b>Ipv6FlowClassifier</b>
+    which returns a vector of pairs (dscp,count), each of which indicates how many packets with the
+    associated dscp value have been classified for a given flow.
+</li>
 </ul>
 <h2>Changes to existing API:</h2>
 <ul>
--- a/examples/traffic-control/traffic-control.cc	Wed Mar 08 18:02:07 2017 +0100
+++ b/examples/traffic-control/traffic-control.cc	Wed Mar 08 18:02:10 2017 +0100
@@ -153,7 +153,9 @@
   onoff.SetAttribute ("DataRate", StringValue ("50Mbps")); //bit/s
   ApplicationContainer apps;
 
-  AddressValue remoteAddress (InetSocketAddress (interfaces.GetAddress (0), port));
+  InetSocketAddress rmt (interfaces.GetAddress (0), port);
+  rmt.SetTos (0xb8);
+  AddressValue remoteAddress (rmt);
   onoff.SetAttribute ("Remote", remoteAddress);
   apps.Add (onoff.Install (nodes.Get (1)));
   apps.Start (Seconds (1.0));
@@ -194,6 +196,12 @@
   std::cout << "  Throughput: " << stats[1].rxBytes * 8.0 / (stats[1].timeLastRxPacket.GetSeconds () - stats[1].timeFirstRxPacket.GetSeconds ()) / 1000000 << " Mbps" << std::endl;
   std::cout << "  Mean delay:   " << stats[1].delaySum.GetSeconds () / stats[1].rxPackets << std::endl;
   std::cout << "  Mean jitter:   " << stats[1].jitterSum.GetSeconds () / (stats[1].rxPackets - 1) << std::endl;
+  auto dscpVec = classifier->GetDscpCounts (1);
+  for (auto p : dscpVec)
+    {
+      std::cout << "  DSCP value:   0x" << std::hex << static_cast<uint32_t>(p.first) << std::dec
+                << "  count:   "<< p.second << std::endl;
+    }
 
   Simulator::Destroy ();
 
--- a/src/flow-monitor/model/ipv4-flow-classifier.cc	Wed Mar 08 18:02:07 2017 +0100
+++ b/src/flow-monitor/model/ipv4-flow-classifier.cc	Wed Mar 08 18:02:10 2017 +0100
@@ -23,6 +23,7 @@
 #include "ipv4-flow-classifier.h"
 #include "ns3/udp-header.h"
 #include "ns3/tcp-header.h"
+#include <algorithm>
 
 namespace ns3 {
 
@@ -156,12 +157,24 @@
       FlowId newFlowId = GetNewFlowId ();
       insert.first->second = newFlowId;
       m_flowPktIdMap[newFlowId] = 0;
+      m_flowDscpMap[newFlowId];
     }
   else
     {
       m_flowPktIdMap[insert.first->second] ++;
     }
 
+  // increment the counter of packets with the same DSCP value
+  Ipv4Header::DscpType dscp = ipHeader.GetDscp ();
+  std::pair<std::map<Ipv4Header::DscpType, uint32_t>::iterator, bool> dscpInserter
+    = m_flowDscpMap[insert.first->second].insert (std::pair<Ipv4Header::DscpType, uint32_t> (dscp, 1));
+
+  // if the insertion did not succeed, we need to increment the counter
+  if (!dscpInserter.second)
+    {
+      m_flowDscpMap[insert.first->second][dscp] ++;
+    }
+
   *out_flowId = insert.first->second;
   *out_packetId = m_flowPktIdMap[*out_flowId];
 
@@ -185,6 +198,29 @@
   return retval;
 }
 
+bool
+Ipv4FlowClassifier::SortByCount::operator() (std::pair<Ipv4Header::DscpType, uint32_t> left,
+                                             std::pair<Ipv4Header::DscpType, uint32_t> right)
+{
+  return left.second > right.second;
+}
+
+std::vector<std::pair<Ipv4Header::DscpType, uint32_t> >
+Ipv4FlowClassifier::GetDscpCounts (FlowId flowId) const
+{
+  std::map<FlowId, std::map<Ipv4Header::DscpType, uint32_t> >::const_iterator flow
+    = m_flowDscpMap.find (flowId);
+
+  if (flow == m_flowDscpMap.end ())
+    {
+      NS_FATAL_ERROR ("Could not find the flow with ID " << flowId);
+    }
+
+  std::vector<std::pair<Ipv4Header::DscpType, uint32_t> > v (flow->second.begin (), flow->second.end ());
+  std::sort (v.begin (), v.end (), SortByCount ());
+  return v;
+}
+
 void
 Ipv4FlowClassifier::SerializeToXmlStream (std::ostream &os, uint16_t indent) const
 {
@@ -200,8 +236,24 @@
          << " destinationAddress=\"" << iter->first.destinationAddress << "\""
          << " protocol=\"" << int(iter->first.protocol) << "\""
          << " sourcePort=\"" << iter->first.sourcePort << "\""
-         << " destinationPort=\"" << iter->first.destinationPort << "\""
-         << " />\n";
+         << " destinationPort=\"" << iter->first.destinationPort << "\">\n";
+
+      indent += 2;
+      std::map<FlowId, std::map<Ipv4Header::DscpType, uint32_t> >::const_iterator flow
+        = m_flowDscpMap.find (iter->second);
+
+      if (flow != m_flowDscpMap.end ())
+        {
+          for (std::map<Ipv4Header::DscpType, uint32_t>::const_iterator i = flow->second.begin (); i != flow->second.end (); i++)
+            {
+              Indent (os, indent);
+              os << "<Dscp value=\"0x" << std::hex << static_cast<uint32_t> (i->first) << "\""
+                 << " packets=\"" << std::dec << i->second << "\" />\n";
+            }
+        }
+
+      indent -= 2;
+      Indent (os, indent); os << "</Flow>\n";
     }
 
   indent -= 2;
--- a/src/flow-monitor/model/ipv4-flow-classifier.h	Wed Mar 08 18:02:07 2017 +0100
+++ b/src/flow-monitor/model/ipv4-flow-classifier.h	Wed Mar 08 18:02:10 2017 +0100
@@ -69,6 +69,21 @@
   /// \returns the FiveTuple corresponding to flowId
   FiveTuple FindFlow (FlowId flowId) const;
 
+  /// Comparator used to sort the vector of DSCP values
+  class SortByCount
+  {
+  public:
+    bool operator() (std::pair<Ipv4Header::DscpType, uint32_t> left,
+                     std::pair<Ipv4Header::DscpType, uint32_t> right);
+  };
+
+  /// \brief get the DSCP values of the packets belonging to the flow with the
+  /// given FlowId, sorted in decreasing order of number of packets seen with
+  /// that DSCP value
+  /// \param flowId the identifier of the flow of interest
+  /// \returns the vector of DSCP values
+  std::vector<std::pair<Ipv4Header::DscpType, uint32_t> > GetDscpCounts (FlowId flowId) const;
+
   virtual void SerializeToXmlStream (std::ostream &os, uint16_t indent) const;
 
 private:
@@ -77,6 +92,8 @@
   std::map<FiveTuple, FlowId> m_flowMap;
   /// Map to FlowIds to FlowPacketId
   std::map<FlowId, FlowPacketId> m_flowPktIdMap;
+  /// Map FlowIds to (DSCP value, packet count) pairs
+  std::map<FlowId, std::map<Ipv4Header::DscpType, uint32_t> > m_flowDscpMap;
 
 };
 
--- a/src/flow-monitor/model/ipv6-flow-classifier.cc	Wed Mar 08 18:02:07 2017 +0100
+++ b/src/flow-monitor/model/ipv6-flow-classifier.cc	Wed Mar 08 18:02:10 2017 +0100
@@ -24,6 +24,7 @@
 #include "ipv6-flow-classifier.h"
 #include "ns3/udp-header.h"
 #include "ns3/tcp-header.h"
+#include <algorithm>
 
 namespace ns3 {
 
@@ -157,12 +158,24 @@
       FlowId newFlowId = GetNewFlowId ();
       insert.first->second = newFlowId;
       m_flowPktIdMap[newFlowId] = 0;
+      m_flowDscpMap[newFlowId];
     }
   else
     {
       m_flowPktIdMap[insert.first->second] ++;
     }
 
+  // increment the counter of packets with the same DSCP value
+  Ipv6Header::DscpType dscp = ipHeader.GetDscp ();
+  std::pair<std::map<Ipv6Header::DscpType, uint32_t>::iterator, bool> dscpInserter
+    = m_flowDscpMap[insert.first->second].insert (std::pair<Ipv6Header::DscpType, uint32_t> (dscp, 1));
+
+  // if the insertion did not succeed, we need to increment the counter
+  if (!dscpInserter.second)
+    {
+      m_flowDscpMap[insert.first->second][dscp] ++;
+    }
+
   *out_flowId = insert.first->second;
   *out_packetId = m_flowPktIdMap[*out_flowId];
 
@@ -186,6 +199,29 @@
   return retval;
 }
 
+bool
+Ipv6FlowClassifier::SortByCount::operator() (std::pair<Ipv6Header::DscpType, uint32_t> left,
+                                             std::pair<Ipv6Header::DscpType, uint32_t> right)
+{
+  return left.second > right.second;
+}
+
+std::vector<std::pair<Ipv6Header::DscpType, uint32_t> >
+Ipv6FlowClassifier::GetDscpCounts (FlowId flowId) const
+{
+  std::map<FlowId, std::map<Ipv6Header::DscpType, uint32_t> >::const_iterator flow
+    = m_flowDscpMap.find (flowId);
+
+  if (flow == m_flowDscpMap.end ())
+    {
+      NS_FATAL_ERROR ("Could not find the flow with ID " << flowId);
+    }
+
+  std::vector<std::pair<Ipv6Header::DscpType, uint32_t> > v (flow->second.begin (), flow->second.end ());
+  std::sort (v.begin (), v.end (), SortByCount ());
+  return v;
+}
+
 void
 Ipv6FlowClassifier::SerializeToXmlStream (std::ostream &os, uint16_t indent) const
 {
@@ -201,8 +237,24 @@
          << " destinationAddress=\"" << iter->first.destinationAddress << "\""
          << " protocol=\"" << int(iter->first.protocol) << "\""
          << " sourcePort=\"" << iter->first.sourcePort << "\""
-         << " destinationPort=\"" << iter->first.destinationPort << "\""
-         << " />\n";
+         << " destinationPort=\"" << iter->first.destinationPort << "\">\n";
+
+      indent += 2;
+      std::map<FlowId, std::map<Ipv6Header::DscpType, uint32_t> >::const_iterator flow
+        = m_flowDscpMap.find (iter->second);
+
+      if (flow != m_flowDscpMap.end ())
+        {
+          for (std::map<Ipv6Header::DscpType, uint32_t>::const_iterator i = flow->second.begin (); i != flow->second.end (); i++)
+            {
+              Indent (os, indent);
+              os << "<Dscp value=\"0x" << std::hex << static_cast<uint32_t> (i->first) << "\""
+                 << " packets=\"" << std::dec << i->second << "\" />\n";
+            }
+        }
+
+      indent -= 2;
+      Indent (os, indent); os << "</Flow>\n";
     }
 
   indent -= 2;
--- a/src/flow-monitor/model/ipv6-flow-classifier.h	Wed Mar 08 18:02:07 2017 +0100
+++ b/src/flow-monitor/model/ipv6-flow-classifier.h	Wed Mar 08 18:02:10 2017 +0100
@@ -70,6 +70,21 @@
   /// \returns the FiveTuple corresponding to flowId
   FiveTuple FindFlow (FlowId flowId) const;
 
+  /// Comparator used to sort the vector of DSCP values
+  class SortByCount
+  {
+  public:
+    bool operator() (std::pair<Ipv6Header::DscpType, uint32_t> left,
+                     std::pair<Ipv6Header::DscpType, uint32_t> right);
+  };
+
+  /// \brief get the DSCP values of the packets belonging to the flow with the
+  /// given FlowId, sorted in decreasing order of number of packets seen with
+  /// that DSCP value
+  /// \param flowId the identifier of the flow of interest
+  /// \returns the vector of DSCP values
+  std::vector<std::pair<Ipv6Header::DscpType, uint32_t> > GetDscpCounts (FlowId flowId) const;
+
   virtual void SerializeToXmlStream (std::ostream &os, uint16_t indent) const;
 
 private:
@@ -78,6 +93,8 @@
   std::map<FiveTuple, FlowId> m_flowMap;
   /// Map to FlowIds to FlowPacketId
   std::map<FlowId, FlowPacketId> m_flowPktIdMap;
+  /// Map FlowIds to (DSCP value, packet count) pairs
+  std::map<FlowId, std::map<Ipv6Header::DscpType, uint32_t> > m_flowDscpMap;
 
 };