blob: 84055f1f6a71dc85e50d35145bc608161bec80e7 [file] [log] [blame]
Vince Lehman8a4c29e2016-07-11 08:49:35 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -05002/*
Davide Pesaventob8bd5ee2019-02-03 22:53:40 -05003 * Copyright (c) 2014-2019, Regents of the University of California,
Vince Lehman8a4c29e2016-07-11 08:49:35 +00004 * 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"
Ashlesh Gawande2a73f352016-12-01 15:37:03 +000027#include "algorithm.hpp"
Davide Pesavento3dade002019-03-19 11:29:56 -060028#include "daemon/global.hpp"
Vince Lehman8a4c29e2016-07-11 08:49:35 +000029
Davide Pesaventob8bd5ee2019-02-03 22:53:40 -050030#include <ndn-cxx/util/random.hpp>
31
Vince Lehman8a4c29e2016-07-11 08:49:35 +000032namespace nfd {
33namespace fw {
34namespace asf {
35
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -050036constexpr time::milliseconds ProbingModule::DEFAULT_PROBING_INTERVAL;
37constexpr time::milliseconds ProbingModule::MIN_PROBING_INTERVAL;
Vince Lehman8a4c29e2016-07-11 08:49:35 +000038
39static_assert(ProbingModule::DEFAULT_PROBING_INTERVAL < AsfMeasurements::MEASUREMENTS_LIFETIME,
40 "ProbingModule::DEFAULT_PROBING_INTERVAL must be less than AsfMeasurements::MEASUREMENTS_LIFETIME");
41
42ProbingModule::ProbingModule(AsfMeasurements& measurements)
43 : m_probingInterval(DEFAULT_PROBING_INTERVAL)
44 , m_measurements(measurements)
45{
46}
47
48void
Junxiao Shi8d843142016-07-11 22:42:42 +000049ProbingModule::scheduleProbe(const fib::Entry& fibEntry, const time::milliseconds& interval)
Vince Lehman8a4c29e2016-07-11 08:49:35 +000050{
Junxiao Shifc021862016-08-25 21:51:18 +000051 Name prefix = fibEntry.getPrefix();
Vince Lehman8a4c29e2016-07-11 08:49:35 +000052
53 // Set the probing flag for the namespace to true after passed interval of time
Davide Pesavento3dade002019-03-19 11:29:56 -060054 getScheduler().schedule(interval, [this, prefix] {
Junxiao Shifc021862016-08-25 21:51:18 +000055 NamespaceInfo* info = m_measurements.getNamespaceInfo(prefix);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000056
57 if (info == nullptr) {
58 // fib::Entry with the passed prefix has been removed or the fib::Entry has
59 // a name that is not controlled by the AsfStrategy
60 return;
61 }
62 else {
63 info->setIsProbingDue(true);
64 }
65 });
66}
67
Junxiao Shia6de4292016-07-12 02:08:10 +000068Face*
Davide Pesavento3dade002019-03-19 11:29:56 -060069ProbingModule::getFaceToProbe(const Face& inFace, const Interest& interest,
70 const fib::Entry& fibEntry, const Face& faceUsed)
Vince Lehman8a4c29e2016-07-11 08:49:35 +000071{
72 FaceInfoFacePairSet rankedFaces(
Davide Pesaventoe4b22382018-06-10 14:37:24 -040073 [] (const auto& pairLhs, const auto& pairRhs) -> bool {
Vince Lehman8a4c29e2016-07-11 08:49:35 +000074 // Sort by RTT
75 // If a face has timed-out, rank it behind non-timed-out faces
76 FaceInfo& lhs = *pairLhs.first;
77 FaceInfo& rhs = *pairRhs.first;
78
79 return (!lhs.isTimeout() && rhs.isTimeout()) ||
80 (lhs.isTimeout() == rhs.isTimeout() && lhs.getSrtt() < rhs.getSrtt());
81 });
82
83 // Put eligible faces into rankedFaces. If a face does not have an RTT measurement,
84 // immediately pick the face for probing
Davide Pesavento3dade002019-03-19 11:29:56 -060085 for (const auto& hop : fibEntry.getNextHops()) {
Junxiao Shia6de4292016-07-12 02:08:10 +000086 Face& hopFace = hop.getFace();
Vince Lehman8a4c29e2016-07-11 08:49:35 +000087
88 // Don't send probe Interest back to the incoming face or use the same face
Ashlesh Gawande2a73f352016-12-01 15:37:03 +000089 // as the forwarded Interest or use a face that violates scope
90 if (hopFace.getId() == inFace.getId() || hopFace.getId() == faceUsed.getId() ||
91 wouldViolateScope(inFace, interest, hopFace)) {
Vince Lehman8a4c29e2016-07-11 08:49:35 +000092 continue;
93 }
94
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -050095 FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, hopFace.getId());
Vince Lehman8a4c29e2016-07-11 08:49:35 +000096 // If no RTT has been recorded, probe this face
97 if (info == nullptr || !info->hasSrttMeasurement()) {
Junxiao Shia6de4292016-07-12 02:08:10 +000098 return &hopFace;
Vince Lehman8a4c29e2016-07-11 08:49:35 +000099 }
100
101 // Add FaceInfo to container sorted by RTT
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400102 rankedFaces.insert({info, &hopFace});
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000103 }
104
105 if (rankedFaces.empty()) {
106 // No Face to probe
107 return nullptr;
108 }
109
110 return getFaceBasedOnProbability(rankedFaces);
111}
112
113bool
Junxiao Shifc021862016-08-25 21:51:18 +0000114ProbingModule::isProbingNeeded(const fib::Entry& fibEntry, const Interest& interest)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000115{
116 // Return the probing status flag for a namespace
Junxiao Shi8d843142016-07-11 22:42:42 +0000117 NamespaceInfo& info = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000118
119 // If a first probe has not been scheduled for a namespace
120 if (!info.isFirstProbeScheduled()) {
121 // Schedule first probe between 0 and 5 seconds
122 uint64_t interval = getRandomNumber(0, 5000);
123 scheduleProbe(fibEntry, time::milliseconds(interval));
124
125 info.setHasFirstProbeBeenScheduled(true);
126 }
127
128 return info.isProbingDue();
129}
130
131void
Junxiao Shifc021862016-08-25 21:51:18 +0000132ProbingModule::afterForwardingProbe(const fib::Entry& fibEntry, const Interest& interest)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000133{
134 // After probing is done, need to set probing flag to false and
135 // schedule another future probe
Junxiao Shi8d843142016-07-11 22:42:42 +0000136 NamespaceInfo& info = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000137 info.setIsProbingDue(false);
138
139 scheduleProbe(fibEntry, m_probingInterval);
140}
141
Junxiao Shia6de4292016-07-12 02:08:10 +0000142Face*
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000143ProbingModule::getFaceBasedOnProbability(const FaceInfoFacePairSet& rankedFaces)
144{
145 double randomNumber = getRandomNumber(0, 1);
146 uint64_t rankSum = ((rankedFaces.size() + 1) * rankedFaces.size()) / 2;
147
148 uint64_t rank = 1;
149 double offset = 0.0;
150
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400151 for (const auto& pair : rankedFaces) {
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000152 double probability = getProbingProbability(rank++, rankSum, rankedFaces.size());
153
154 // Is the random number within the bounds of this face's probability + the previous faces'
155 // probability?
156 //
157 // e.g. (FaceId: 1, p=0.5), (FaceId: 2, p=0.33), (FaceId: 3, p=0.17)
158 // randomNumber = 0.92
159 //
160 // The face with FaceId: 3 should be picked
161 // (0.68 < 0.5 + 0.33 + 0.17) == true
162 //
163 if (randomNumber <= offset + probability) {
164 // Found face to probe
165 return pair.second;
166 }
167
168 offset += probability;
169 }
170
171 // Given a set of Faces, this method should always select a Face to probe
172 BOOST_ASSERT(false);
173 return nullptr;
174}
175
176double
177ProbingModule::getProbingProbability(uint64_t rank, uint64_t rankSum, uint64_t nFaces)
178{
179 // p = n + 1 - j ; n: # faces
180 // ---------
181 // sum(ranks)
182 return static_cast<double>(nFaces + 1 - rank) / rankSum;
183}
184
185double
186ProbingModule::getRandomNumber(double start, double end)
187{
Davide Pesavento5f47aa62016-10-07 22:09:09 +0200188 std::uniform_real_distribution<double> dist(start, end);
Davide Pesaventob8bd5ee2019-02-03 22:53:40 -0500189 return dist(ndn::random::getRandomNumberEngine());
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000190}
191
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500192void
193ProbingModule::setProbingInterval(size_t probingInterval)
194{
195 if (time::milliseconds(probingInterval) >= MIN_PROBING_INTERVAL) {
196 m_probingInterval = time::milliseconds(probingInterval);
197 }
198 else {
Davide Pesavento19779d82019-02-14 13:40:04 -0500199 NDN_THROW(std::invalid_argument("Probing interval should be >= " +
200 to_string(MIN_PROBING_INTERVAL.count()) + " milliseconds"));
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500201 }
202}
203
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000204} // namespace asf
205} // namespace fw
206} // namespace nfd