Separating dynamic limits into a separate forwarding strategy enhancement

Probabilistic method now treats unknown stats as 0.5
diff --git a/model/fw/dynamic-limits.cc b/model/fw/dynamic-limits.cc
new file mode 100644
index 0000000..f20ff3a
--- /dev/null
+++ b/model/fw/dynamic-limits.cc
@@ -0,0 +1,210 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 University of California, Los Angeles
+ *
+ * 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: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "dynamic-limits.h"
+
+#include "ns3/ndn-l3-protocol.h"
+#include "ns3/ndn-interest-header.h"
+#include "ns3/ndn-content-object-header.h"
+#include "ns3/ndn-pit.h"
+#include "ns3/ndn-pit-entry.h"
+
+#include "ns3/assert.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include "ns3/random-variable.h"
+#include "ns3/double.h"
+
+#include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/lambda/lambda.hpp>
+#include <boost/lambda/bind.hpp>
+namespace ll = boost::lambda;
+
+NS_LOG_COMPONENT_DEFINE ("ndn.fw.DynamicLimits");
+
+namespace ns3 {
+namespace ndn {
+namespace fw {
+
+NS_OBJECT_ENSURE_REGISTERED (DynamicLimits);
+  
+TypeId
+DynamicLimits::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::ndn::fw::DynamicLimits")
+    .SetGroupName ("Ndn")
+    .SetParent <super> ()
+    .AddConstructor <DynamicLimits> ()
+
+    .AddAttribute ("AnnounceLimits", "Enable limit announcement using scope 0 interests",
+                   BooleanValue (false),
+                   MakeBooleanAccessor (&DynamicLimits::m_announceLimits),
+                   MakeBooleanChecker ())
+
+    ;
+  return tid;
+}
+    
+DynamicLimits::DynamicLimits ()
+{
+}
+
+void
+DynamicLimits::DoDispose ()
+{
+  m_announceEvent.Cancel ();
+  
+  super::DoDispose ();
+}
+
+void
+DynamicLimits::NotifyNewAggregate ()
+{
+  super::NotifyNewAggregate ();
+
+  if (m_announceLimits)
+    {
+      if (m_pit != 0 && m_fib != 0)
+        {
+          m_announceEvent = Simulator::Schedule (Seconds (1.0),
+                                                 &DynamicLimits::AnnounceLimits, this);
+        }
+    }
+}
+
+void
+DynamicLimits::OnInterest (Ptr<Face> face,
+                          Ptr<const InterestHeader> header,
+                          Ptr<const Packet> origPacket)
+{
+  if (header->GetScope () != 0)
+    super::OnInterest (face, header, origPacket);
+  else
+    ApplyAnnouncedLimit (face, header);
+}
+
+
+void
+DynamicLimits::AnnounceLimits ()
+{
+  Ptr<L3Protocol> l3 = GetObject<L3Protocol> ();
+  NS_ASSERT (l3 != 0);
+
+  if (l3->GetNFaces () < 2)
+    {
+      m_announceEvent = Simulator::Schedule (Seconds (1.0),
+                                             &DynamicLimits::AnnounceLimits, this);
+      return;
+    }
+  
+  double sumOfWeights = 0;
+  double weightNormalization = 1.0;
+  for (uint32_t faceId = 0; faceId < l3->GetNFaces (); faceId ++)
+    {
+      Ptr<Face> inFace = l3->GetFace (faceId);
+      
+      const ndnSIM::LoadStatsFace &stats = GetStatsTree ()["/"].incoming ().find (inFace)->second;
+      double weight = std::min (1.0, stats.GetSatisfiedRatio ().get<0> ());
+      if (weight < 0) weight = 0.5;
+
+      sumOfWeights += weight;
+    }
+  if (sumOfWeights >= 1)
+    {
+      // disable normalization (not necessary)
+      weightNormalization = 1.0;
+    }
+  else
+    {
+      // sumOfWeights /= (l3->GetNFaces ());
+      weightNormalization = 1 / sumOfWeights;
+    }
+
+  for (Ptr<fib::Entry> entry = m_fib->Begin ();
+       entry != m_fib->End ();
+       entry = m_fib->Next (entry))
+    {
+      InterestHeader announceInterest;
+      announceInterest.SetScope (0); // link-local
+
+      uint32_t totalAllowance = 0;
+      for (fib::FaceMetricContainer::type::iterator fibFace = entry->m_faces.begin ();
+           fibFace != entry->m_faces.end ();
+           fibFace ++)
+        {
+          totalAllowance += fibFace->m_face->GetLimits ().GetMaxLimit ();
+        }
+      
+      if (totalAllowance == 0)
+        {
+          // don't announce anything, there is no limit
+          continue;
+        }
+      
+      for (uint32_t faceId = 0; faceId < l3->GetNFaces (); faceId ++)
+        {
+          Ptr<Face> inFace = l3->GetFace (faceId);
+
+          const ndnSIM::LoadStatsFace &stats = GetStatsTree ()["/"].incoming ().find (inFace)->second;
+          double weight = std::min (1.0, stats.GetSatisfiedRatio ().get<0> ());
+          if (weight < 0) weight = 0.5;
+
+          Ptr<NameComponents> prefixWithLimit = Create<NameComponents> (entry->GetPrefix ());
+          (*prefixWithLimit)
+            ("limit")
+            (static_cast<uint32_t> (std::max (1.0, weightNormalization * weight * totalAllowance)));
+          
+          announceInterest.SetName (prefixWithLimit);
+          // lifetime is 0
+
+          Ptr<Packet> pkt = Create<Packet> ();
+          pkt->AddHeader (announceInterest);
+
+          inFace->Send (pkt);
+        }
+    }
+
+  m_announceEvent = Simulator::Schedule (Seconds (1.0),
+                                         &DynamicLimits::AnnounceLimits, this);
+}
+
+void
+DynamicLimits::ApplyAnnouncedLimit (Ptr<Face> inFace,
+                                   Ptr<const InterestHeader> header)
+{
+  // Ptr<fib::Entry> fibEntry = m_fib->LongestPrefixMatch (header);
+  // if (fibEntry == 0)
+  //   return;
+
+  uint32_t limit = boost::lexical_cast<uint32_t> (header->GetName ().GetLastComponent ());
+  inFace->GetLimits ().SetMaxLimit (limit);
+  
+  // if (Simulator::GetContext () == 6 || Simulator::GetContext () == 4)
+  //   {
+      // std::cerr << Simulator::Now ().ToDouble (Time::S) << "s  from:" << *inFace << " " << *header << std::endl;
+      // std::cerr << header->GetName ().GetLastComponent () << ", " << boost::lexical_cast<uint32_t> (header->GetName ().GetLastComponent ()) << std::endl;
+  //   }
+}
+
+
+} // namespace fw
+} // namespace ndn
+} // namespace ns3