examples: New example with custom strategy "random-load-balancer-strategy"

Based on Steve DiBenedetto's tutorial code https://github.com/dibenede/ndn-tutorial-gec21
diff --git a/examples/ndn-load-balancer.cpp b/examples/ndn-load-balancer.cpp
new file mode 100644
index 0000000..46ea740
--- /dev/null
+++ b/examples/ndn-load-balancer.cpp
@@ -0,0 +1,118 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2011-2015  Regents of the University of California.
+ *
+ * This file is part of ndnSIM. See AUTHORS for complete list of ndnSIM authors and
+ * contributors.
+ *
+ * ndnSIM is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * ndnSIM 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
+ * ndnSIM, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+// ndn-load-balancer.cpp
+
+#include "ns3/core-module.h"
+#include "ns3/network-module.h"
+#include "ns3/ndnSIM-module.h"
+
+#include "ndn-load-balancer/random-load-balancer-strategy.hpp"
+
+using namespace ns3;
+
+/**
+ * This scenario simulates a load balancer topology (using topology reader module)
+ *
+ *               ( ) ----- ( ) ---- (consumer)
+ *                |
+ *        ------ ( ) -----
+ *        |               |
+ *    (producer) ---- (producer)
+ *
+ * All links are 1Mbps with propagation 10ms delay.
+ *
+ * FIB is populated using NdnGlobalRoutingHelper.
+ *
+ * Consumer requests data from the two producers with frequency 10 interests per
+ * second (interests contain constantly increasing sequence number).
+ *
+ * For every received interest, a load balancing operation is performed
+ * (based on a custom forwarding strategy) and the selected producer
+ * replies with a data packet, containing 1024 bytes of virtual payload.
+ *
+ * To run scenario and see what is happening, use the following command:
+ *
+ *     NS_LOG=ndn.Consumer:ndn.Producer ./waf --run=ndn-load-balancer
+ */
+
+using ns3::ndn::StackHelper;
+using ns3::ndn::AppHelper;
+using ns3::ndn::GlobalRoutingHelper;
+using ns3::ndn::StrategyChoiceHelper;
+using ns3::AnnotatedTopologyReader;
+
+int
+main(int argc, char* argv[])
+{
+  CommandLine cmd;
+  cmd.Parse(argc, argv);
+
+  AnnotatedTopologyReader topologyReader("", 25);
+  topologyReader.SetFileName("src/ndnSIM/examples/topologies/topo-load-balancer.txt");
+  topologyReader.Read();
+
+  // Install NDN stack on all nodes
+  StackHelper ndnHelper;
+  ndnHelper.InstallAll();
+
+  // Installing global routing interface on all nodes
+  GlobalRoutingHelper ndnGlobalRoutingHelper;
+  ndnGlobalRoutingHelper.InstallAll();
+
+  // Getting containers for the consumer/producer
+  Ptr<Node> producer1 = Names::Find<Node>("UCLA-1");
+  Ptr<Node> producer2 = Names::Find<Node>("UCLA-2");
+  NodeContainer consumerNodes;
+  consumerNodes.Add(Names::Find<Node>("CSU-1"));
+
+  // Install NDN applications
+  std::string prefix = "/ucla/hello";
+
+  AppHelper consumerHelper("ns3::ndn::ConsumerCbr");
+  consumerHelper.SetPrefix(prefix);
+  consumerHelper.SetAttribute("Frequency", StringValue("100")); // 100 interests a second
+  consumerHelper.Install(consumerNodes);
+
+  AppHelper producerHelper("ns3::ndn::Producer");
+  producerHelper.SetPrefix(prefix);
+  producerHelper.SetAttribute("PayloadSize", StringValue("1024"));
+  producerHelper.Install(producer1);
+  producerHelper.Install(producer2);
+
+  // Install random-load-balancer forwarding strategy in
+  // node UCLA-HUB
+  StrategyChoiceHelper strategyChoiceHelper;
+  strategyChoiceHelper.Install<nfd::fw::RandomLoadBalancerStrategy>(Names::Find<Node>("UCLA-HUB"),
+                                                                    prefix);
+
+  // Add /prefix origins to ndn::GlobalRouter
+  ndnGlobalRoutingHelper.AddOrigins(prefix, producer1);
+  ndnGlobalRoutingHelper.AddOrigins(prefix, producer2);
+
+  // Calculate and install FIBs
+  GlobalRoutingHelper::CalculateRoutes();
+
+  Simulator::Stop(Seconds(1.0));
+
+  Simulator::Run();
+  Simulator::Destroy();
+
+  return 0;
+}
diff --git a/examples/ndn-load-balancer/random-load-balancer-strategy.cpp b/examples/ndn-load-balancer/random-load-balancer-strategy.cpp
new file mode 100644
index 0000000..6083dd3
--- /dev/null
+++ b/examples/ndn-load-balancer/random-load-balancer-strategy.cpp
@@ -0,0 +1,100 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California,
+ *                      Arizona Board of Regents,
+ *                      Colorado State University,
+ *                      University Pierre & Marie Curie, Sorbonne University,
+ *                      Washington University in St. Louis,
+ *                      Beijing Institute of Technology,
+ *                      The University of Memphis
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD 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
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "random-load-balancer-strategy.hpp"
+
+#include <boost/random/uniform_int_distribution.hpp>
+
+#include <ndn-cxx/util/random.hpp>
+
+#include "core/logger.hpp"
+
+NFD_LOG_INIT("RandomLoadBalancerStrategy");
+
+namespace nfd {
+namespace fw {
+
+const Name
+  RandomLoadBalancerStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/random-load-balancer");
+
+RandomLoadBalancerStrategy::RandomLoadBalancerStrategy(Forwarder& forwarder, const Name& name)
+  : Strategy(forwarder, name)
+{
+}
+
+RandomLoadBalancerStrategy::~RandomLoadBalancerStrategy()
+{
+}
+
+static bool
+canForwardToNextHop(shared_ptr<pit::Entry> pitEntry, const fib::NextHop& nexthop)
+{
+  return pitEntry->canForwardTo(*nexthop.getFace());
+}
+
+static bool
+hasFaceForForwarding(const fib::NextHopList& nexthops, shared_ptr<pit::Entry>& pitEntry)
+{
+  return std::find_if(nexthops.begin(), nexthops.end(), bind(&canForwardToNextHop, pitEntry, _1))
+         != nexthops.end();
+}
+
+void
+RandomLoadBalancerStrategy::afterReceiveInterest(const Face& inFace, const Interest& interest,
+                                                 shared_ptr<fib::Entry> fibEntry,
+                                                 shared_ptr<pit::Entry> pitEntry)
+{
+  NFD_LOG_TRACE("afterReceiveInterest");
+
+  if (pitEntry->hasUnexpiredOutRecords()) {
+    // not a new Interest, don't forward
+    return;
+  }
+
+  const fib::NextHopList& nexthops = fibEntry->getNextHops();
+
+  // Ensure there is at least 1 Face is available for forwarding
+  if (!hasFaceForForwarding(nexthops, pitEntry)) {
+    this->rejectPendingInterest(pitEntry);
+    return;
+  }
+
+  fib::NextHopList::const_iterator selected;
+  do {
+    boost::random::uniform_int_distribution<> dist(0, nexthops.size() - 1);
+    const size_t randomIndex = dist(m_randomGenerator);
+
+    uint64_t currentIndex = 0;
+
+    for (selected = nexthops.begin(); selected != nexthops.end() && currentIndex != randomIndex;
+         ++selected, ++currentIndex) {
+    }
+  } while (!canForwardToNextHop(pitEntry, *selected));
+
+  this->sendInterest(pitEntry, selected->getFace());
+}
+
+} // namespace fw
+} // namespace nfd
diff --git a/examples/ndn-load-balancer/random-load-balancer-strategy.hpp b/examples/ndn-load-balancer/random-load-balancer-strategy.hpp
new file mode 100644
index 0000000..2d45831
--- /dev/null
+++ b/examples/ndn-load-balancer/random-load-balancer-strategy.hpp
@@ -0,0 +1,56 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California,
+ *                      Arizona Board of Regents,
+ *                      Colorado State University,
+ *                      University Pierre & Marie Curie, Sorbonne University,
+ *                      Washington University in St. Louis,
+ *                      Beijing Institute of Technology,
+ *                      The University of Memphis
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD 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
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NDNSIM_EXAMPLES_NDN_LOAD_BALANCER_RANDOM_LOAD_BALANCER_STRATEGY_HPP
+#define NDNSIM_EXAMPLES_NDN_LOAD_BALANCER_RANDOM_LOAD_BALANCER_STRATEGY_HPP
+
+#include <boost/random/mersenne_twister.hpp>
+#include "face/face.hpp"
+#include "fw/strategy.hpp"
+
+namespace nfd {
+namespace fw {
+
+class RandomLoadBalancerStrategy : public Strategy {
+public:
+  RandomLoadBalancerStrategy(Forwarder& forwarder, const Name& name = STRATEGY_NAME);
+
+  virtual ~RandomLoadBalancerStrategy();
+
+  virtual void
+  afterReceiveInterest(const Face& inFace, const Interest& interest,
+                       shared_ptr<fib::Entry> fibEntry, shared_ptr<pit::Entry> pitEntry);
+
+public:
+  static const Name STRATEGY_NAME;
+
+protected:
+  boost::random::mt19937 m_randomGenerator;
+};
+
+} // namespace fw
+} // namespace nfd
+
+#endif // NDNSIM_EXAMPLES_NDN_LOAD_BALANCER_RANDOM_LOAD_BALANCER_STRATEGY_HPP
diff --git a/examples/topologies/topo-load-balancer.txt b/examples/topologies/topo-load-balancer.txt
new file mode 100644
index 0000000..f05ec96
--- /dev/null
+++ b/examples/topologies/topo-load-balancer.txt
@@ -0,0 +1,52 @@
+# topo-load-balancer.txt
+
+#
+#                           /----\
+#                           |CSU |
+#                  <---->   |HUB |  <---->
+#                 ^         \----/       ^
+#                 |                      |  1Mbps/10ms delay
+#                 v                      v
+#               /----\                /--------\
+#               |UCLA|                |Consumer|
+#               | HUB|                |  CSU-1 |
+#        <----> \----/  <---->        \--------/
+#       ^                     ^
+#       |                     |
+#       v                     v
+#   /--------\            /--------\
+#   |Producer|            |Producer|
+#   | UCLA-1 |            | UCLA-2 |
+#   \--------/            \--------/
+#
+
+# any empty lines and lines starting with '#' symbol is ignored
+#
+# The file should contain exactly two sections: router and link, each starting with the corresponding keyword
+#
+# router section defines topology nodes and their relative positions (e.g., to use in visualizer)
+router
+
+# each line in this section represents one router and should have the following data
+# node   comment    yPos    xPos
+CSU-1    NA          3       5
+CSU-HUB  NA          5       3
+UCLA-HUB NA          3       1
+UCLA-1   NA          0       0
+UCLA-2   NA          0       2
+
+# Note that `node` can be any string. It is possible to access to the node by name using Names::Find, see examples.
+
+# link section defines point-to-point links between nodes and characteristics of these links
+link
+
+# Each line should be in the following format (only first two are required, the rest can be omitted)
+# srcNode   dstNode     bandwidth   metric  delay   queue
+# bandwidth: link bandwidth
+# metric: routing metric
+# delay:  link delay
+# queue:  MaxPackets for transmission queue on the link (both directions)
+CSU-1       CSU-HUB     1Mbps       1       10ms    10
+CSU-HUB     UCLA-HUB    1Mbps       1       10ms    10
+UCLA-HUB    UCLA-1      1Mbps       1       10ms    10
+UCLA-HUB    UCLA-2      1Mbps       1       10ms    10