blob: 485a3e998b4af2af1d723b827468790be716e254 [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"
Junxiao Shi9f5b01d2016-08-05 03:54:28 +000027#include "core/random.hpp"
Vince Lehman8a4c29e2016-07-11 08:49:35 +000028
Vince Lehman8a4c29e2016-07-11 08:49:35 +000029namespace nfd {
30namespace fw {
31namespace asf {
32
33constexpr time::seconds ProbingModule::DEFAULT_PROBING_INTERVAL;
34
35static_assert(ProbingModule::DEFAULT_PROBING_INTERVAL < AsfMeasurements::MEASUREMENTS_LIFETIME,
36 "ProbingModule::DEFAULT_PROBING_INTERVAL must be less than AsfMeasurements::MEASUREMENTS_LIFETIME");
37
38ProbingModule::ProbingModule(AsfMeasurements& measurements)
39 : m_probingInterval(DEFAULT_PROBING_INTERVAL)
40 , m_measurements(measurements)
41{
42}
43
44void
Junxiao Shi8d843142016-07-11 22:42:42 +000045ProbingModule::scheduleProbe(const fib::Entry& fibEntry, const time::milliseconds& interval)
Vince Lehman8a4c29e2016-07-11 08:49:35 +000046{
Junxiao Shifc021862016-08-25 21:51:18 +000047 Name prefix = fibEntry.getPrefix();
Vince Lehman8a4c29e2016-07-11 08:49:35 +000048
49 // Set the probing flag for the namespace to true after passed interval of time
50 scheduler::schedule(interval, [this, prefix] {
Junxiao Shifc021862016-08-25 21:51:18 +000051 NamespaceInfo* info = m_measurements.getNamespaceInfo(prefix);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000052
53 if (info == nullptr) {
54 // fib::Entry with the passed prefix has been removed or the fib::Entry has
55 // a name that is not controlled by the AsfStrategy
56 return;
57 }
58 else {
59 info->setIsProbingDue(true);
60 }
61 });
62}
63
Junxiao Shia6de4292016-07-12 02:08:10 +000064Face*
Vince Lehman8a4c29e2016-07-11 08:49:35 +000065ProbingModule::getFaceToProbe(const Face& inFace,
66 const Interest& interest,
Junxiao Shi8d843142016-07-11 22:42:42 +000067 const fib::Entry& fibEntry,
Vince Lehman8a4c29e2016-07-11 08:49:35 +000068 const Face& faceUsed)
69{
70 FaceInfoFacePairSet rankedFaces(
71 [] (FaceInfoFacePair pairLhs, FaceInfoFacePair pairRhs) -> bool {
72 // Sort by RTT
73 // If a face has timed-out, rank it behind non-timed-out faces
74 FaceInfo& lhs = *pairLhs.first;
75 FaceInfo& rhs = *pairRhs.first;
76
77 return (!lhs.isTimeout() && rhs.isTimeout()) ||
78 (lhs.isTimeout() == rhs.isTimeout() && lhs.getSrtt() < rhs.getSrtt());
79 });
80
81 // Put eligible faces into rankedFaces. If a face does not have an RTT measurement,
82 // immediately pick the face for probing
Junxiao Shi8d843142016-07-11 22:42:42 +000083 for (const fib::NextHop& hop : fibEntry.getNextHops()) {
Junxiao Shia6de4292016-07-12 02:08:10 +000084 Face& hopFace = hop.getFace();
Vince Lehman8a4c29e2016-07-11 08:49:35 +000085
86 // Don't send probe Interest back to the incoming face or use the same face
87 // as the forwarded Interest
Junxiao Shia6de4292016-07-12 02:08:10 +000088 if (hopFace.getId() == inFace.getId() || hopFace.getId() == faceUsed.getId()) {
Vince Lehman8a4c29e2016-07-11 08:49:35 +000089 continue;
90 }
91
Junxiao Shia6de4292016-07-12 02:08:10 +000092 FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, hopFace);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000093
94 // If no RTT has been recorded, probe this face
95 if (info == nullptr || !info->hasSrttMeasurement()) {
Junxiao Shia6de4292016-07-12 02:08:10 +000096 return &hopFace;
Vince Lehman8a4c29e2016-07-11 08:49:35 +000097 }
98
99 // Add FaceInfo to container sorted by RTT
Junxiao Shia6de4292016-07-12 02:08:10 +0000100 rankedFaces.insert(std::make_pair(info, &hopFace));
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000101 }
102
103 if (rankedFaces.empty()) {
104 // No Face to probe
105 return nullptr;
106 }
107
108 return getFaceBasedOnProbability(rankedFaces);
109}
110
111bool
Junxiao Shifc021862016-08-25 21:51:18 +0000112ProbingModule::isProbingNeeded(const fib::Entry& fibEntry, const Interest& interest)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000113{
114 // Return the probing status flag for a namespace
Junxiao Shi8d843142016-07-11 22:42:42 +0000115 NamespaceInfo& info = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000116
117 // If a first probe has not been scheduled for a namespace
118 if (!info.isFirstProbeScheduled()) {
119 // Schedule first probe between 0 and 5 seconds
120 uint64_t interval = getRandomNumber(0, 5000);
121 scheduleProbe(fibEntry, time::milliseconds(interval));
122
123 info.setHasFirstProbeBeenScheduled(true);
124 }
125
126 return info.isProbingDue();
127}
128
129void
Junxiao Shifc021862016-08-25 21:51:18 +0000130ProbingModule::afterForwardingProbe(const fib::Entry& fibEntry, const Interest& interest)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000131{
132 // After probing is done, need to set probing flag to false and
133 // schedule another future probe
Junxiao Shi8d843142016-07-11 22:42:42 +0000134 NamespaceInfo& info = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000135 info.setIsProbingDue(false);
136
137 scheduleProbe(fibEntry, m_probingInterval);
138}
139
Junxiao Shia6de4292016-07-12 02:08:10 +0000140Face*
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000141ProbingModule::getFaceBasedOnProbability(const FaceInfoFacePairSet& rankedFaces)
142{
143 double randomNumber = getRandomNumber(0, 1);
144 uint64_t rankSum = ((rankedFaces.size() + 1) * rankedFaces.size()) / 2;
145
146 uint64_t rank = 1;
147 double offset = 0.0;
148
149 for (const FaceInfoFacePair pair : rankedFaces) {
150 double probability = getProbingProbability(rank++, rankSum, rankedFaces.size());
151
152 // Is the random number within the bounds of this face's probability + the previous faces'
153 // probability?
154 //
155 // e.g. (FaceId: 1, p=0.5), (FaceId: 2, p=0.33), (FaceId: 3, p=0.17)
156 // randomNumber = 0.92
157 //
158 // The face with FaceId: 3 should be picked
159 // (0.68 < 0.5 + 0.33 + 0.17) == true
160 //
161 if (randomNumber <= offset + probability) {
162 // Found face to probe
163 return pair.second;
164 }
165
166 offset += probability;
167 }
168
169 // Given a set of Faces, this method should always select a Face to probe
170 BOOST_ASSERT(false);
171 return nullptr;
172}
173
174double
175ProbingModule::getProbingProbability(uint64_t rank, uint64_t rankSum, uint64_t nFaces)
176{
177 // p = n + 1 - j ; n: # faces
178 // ---------
179 // sum(ranks)
180 return static_cast<double>(nFaces + 1 - rank) / rankSum;
181}
182
183double
184ProbingModule::getRandomNumber(double start, double end)
185{
Davide Pesavento5f47aa62016-10-07 22:09:09 +0200186 std::uniform_real_distribution<double> dist(start, end);
187 return dist(getGlobalRng());
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000188}
189
190} // namespace asf
191} // namespace fw
192} // namespace nfd