blob: 4be41f0de86671763f642cf9307e3be8b9c29a4e [file] [log] [blame]
Vince Lehman8a4c29e2016-07-11 08:49:35 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014-2016, Regents of the University of California,
4 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
10 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24 */
25
26#include "asf-probing-module.hpp"
27
28#include "random.hpp"
29
30#include <boost/random/uniform_real_distribution.hpp>
31
32namespace nfd {
33namespace fw {
34namespace asf {
35
36constexpr time::seconds ProbingModule::DEFAULT_PROBING_INTERVAL;
37
38static_assert(ProbingModule::DEFAULT_PROBING_INTERVAL < AsfMeasurements::MEASUREMENTS_LIFETIME,
39 "ProbingModule::DEFAULT_PROBING_INTERVAL must be less than AsfMeasurements::MEASUREMENTS_LIFETIME");
40
41ProbingModule::ProbingModule(AsfMeasurements& measurements)
42 : m_probingInterval(DEFAULT_PROBING_INTERVAL)
43 , m_measurements(measurements)
44{
45}
46
47void
48ProbingModule::scheduleProbe(shared_ptr<fib::Entry> fibEntry, const time::milliseconds& interval)
49{
50 ndn::Name prefix = fibEntry->getPrefix();
51
52 // Set the probing flag for the namespace to true after passed interval of time
53 scheduler::schedule(interval, [this, prefix] {
54 shared_ptr<NamespaceInfo> info = m_measurements.getNamespaceInfo(prefix);
55
56 if (info == nullptr) {
57 // fib::Entry with the passed prefix has been removed or the fib::Entry has
58 // a name that is not controlled by the AsfStrategy
59 return;
60 }
61 else {
62 info->setIsProbingDue(true);
63 }
64 });
65}
66
67shared_ptr<Face>
68ProbingModule::getFaceToProbe(const Face& inFace,
69 const Interest& interest,
70 shared_ptr<fib::Entry> fibEntry,
71 const Face& faceUsed)
72{
73 FaceInfoFacePairSet rankedFaces(
74 [] (FaceInfoFacePair pairLhs, FaceInfoFacePair pairRhs) -> bool {
75 // Sort by RTT
76 // If a face has timed-out, rank it behind non-timed-out faces
77 FaceInfo& lhs = *pairLhs.first;
78 FaceInfo& rhs = *pairRhs.first;
79
80 return (!lhs.isTimeout() && rhs.isTimeout()) ||
81 (lhs.isTimeout() == rhs.isTimeout() && lhs.getSrtt() < rhs.getSrtt());
82 });
83
84 // Put eligible faces into rankedFaces. If a face does not have an RTT measurement,
85 // immediately pick the face for probing
86 for (const fib::NextHop& hop : fibEntry->getNextHops()) {
87 const shared_ptr<Face>& hopFace = hop.getFace();
88
89 // Don't send probe Interest back to the incoming face or use the same face
90 // as the forwarded Interest
91 if (hopFace->getId() == inFace.getId() || hopFace->getId() == faceUsed.getId()) {
92 continue;
93 }
94
95 FaceInfo* info = m_measurements.getFaceInfo(*fibEntry, interest, *hopFace);
96
97 // If no RTT has been recorded, probe this face
98 if (info == nullptr || !info->hasSrttMeasurement()) {
99 return hopFace;
100 }
101
102 // Add FaceInfo to container sorted by RTT
103 rankedFaces.insert(std::make_pair(info, hopFace));
104 }
105
106 if (rankedFaces.empty()) {
107 // No Face to probe
108 return nullptr;
109 }
110
111 return getFaceBasedOnProbability(rankedFaces);
112}
113
114bool
115ProbingModule::isProbingNeeded(shared_ptr<fib::Entry> fibEntry, const ndn::Interest& interest)
116{
117 // Return the probing status flag for a namespace
118 NamespaceInfo& info = m_measurements.getOrCreateNamespaceInfo(*fibEntry, interest);
119
120 // If a first probe has not been scheduled for a namespace
121 if (!info.isFirstProbeScheduled()) {
122 // Schedule first probe between 0 and 5 seconds
123 uint64_t interval = getRandomNumber(0, 5000);
124 scheduleProbe(fibEntry, time::milliseconds(interval));
125
126 info.setHasFirstProbeBeenScheduled(true);
127 }
128
129 return info.isProbingDue();
130}
131
132void
133ProbingModule::afterForwardingProbe(shared_ptr<fib::Entry> fibEntry, const ndn::Interest& interest)
134{
135 // After probing is done, need to set probing flag to false and
136 // schedule another future probe
137 NamespaceInfo& info = m_measurements.getOrCreateNamespaceInfo(*fibEntry, interest);
138 info.setIsProbingDue(false);
139
140 scheduleProbe(fibEntry, m_probingInterval);
141}
142
143shared_ptr<Face>
144ProbingModule::getFaceBasedOnProbability(const FaceInfoFacePairSet& rankedFaces)
145{
146 double randomNumber = getRandomNumber(0, 1);
147 uint64_t rankSum = ((rankedFaces.size() + 1) * rankedFaces.size()) / 2;
148
149 uint64_t rank = 1;
150 double offset = 0.0;
151
152 for (const FaceInfoFacePair pair : rankedFaces) {
153 double probability = getProbingProbability(rank++, rankSum, rankedFaces.size());
154
155 // Is the random number within the bounds of this face's probability + the previous faces'
156 // probability?
157 //
158 // e.g. (FaceId: 1, p=0.5), (FaceId: 2, p=0.33), (FaceId: 3, p=0.17)
159 // randomNumber = 0.92
160 //
161 // The face with FaceId: 3 should be picked
162 // (0.68 < 0.5 + 0.33 + 0.17) == true
163 //
164 if (randomNumber <= offset + probability) {
165 // Found face to probe
166 return pair.second;
167 }
168
169 offset += probability;
170 }
171
172 // Given a set of Faces, this method should always select a Face to probe
173 BOOST_ASSERT(false);
174 return nullptr;
175}
176
177double
178ProbingModule::getProbingProbability(uint64_t rank, uint64_t rankSum, uint64_t nFaces)
179{
180 // p = n + 1 - j ; n: # faces
181 // ---------
182 // sum(ranks)
183 return static_cast<double>(nFaces + 1 - rank) / rankSum;
184}
185
186double
187ProbingModule::getRandomNumber(double start, double end)
188{
189 boost::random::uniform_real_distribution<double> distribution(start, end);
190 return distribution(getGlobalRng());
191}
192
193} // namespace asf
194} // namespace fw
195} // namespace nfd