blob: 0df1712c04877f32f7b24ae1ace036d56144abc0 [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/*
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -04003 * Copyright (c) 2014-2022, 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 Pesavento2cae8ca2019-04-18 20:48:05 -040028#include "common/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
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -040036static_assert(ProbingModule::DEFAULT_PROBING_INTERVAL < AsfMeasurements::MEASUREMENTS_LIFETIME);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000037
38ProbingModule::ProbingModule(AsfMeasurements& measurements)
39 : m_probingInterval(DEFAULT_PROBING_INTERVAL)
40 , m_measurements(measurements)
41{
42}
43
44void
Davide Pesaventoa6f637a2019-08-28 23:23:20 -040045ProbingModule::scheduleProbe(const fib::Entry& fibEntry, 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
Davide Pesavento3dade002019-03-19 11:29:56 -060050 getScheduler().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 if (info == nullptr) {
Davide Pesaventoa6f637a2019-08-28 23:23:20 -040053 // FIB entry with the passed prefix has been removed or
54 // it has a name that is not controlled by the AsfStrategy
Vince Lehman8a4c29e2016-07-11 08:49:35 +000055 }
56 else {
57 info->setIsProbingDue(true);
58 }
59 });
60}
61
Junxiao Shia6de4292016-07-12 02:08:10 +000062Face*
Davide Pesavento3dade002019-03-19 11:29:56 -060063ProbingModule::getFaceToProbe(const Face& inFace, const Interest& interest,
64 const fib::Entry& fibEntry, const Face& faceUsed)
Vince Lehman8a4c29e2016-07-11 08:49:35 +000065{
Davide Pesaventoa6f637a2019-08-28 23:23:20 -040066 FaceInfoFacePairSet rankedFaces;
Vince Lehman8a4c29e2016-07-11 08:49:35 +000067
68 // Put eligible faces into rankedFaces. If a face does not have an RTT measurement,
69 // immediately pick the face for probing
Davide Pesavento3dade002019-03-19 11:29:56 -060070 for (const auto& hop : fibEntry.getNextHops()) {
Junxiao Shia6de4292016-07-12 02:08:10 +000071 Face& hopFace = hop.getFace();
Vince Lehman8a4c29e2016-07-11 08:49:35 +000072
73 // Don't send probe Interest back to the incoming face or use the same face
Ashlesh Gawande2a73f352016-12-01 15:37:03 +000074 // as the forwarded Interest or use a face that violates scope
75 if (hopFace.getId() == inFace.getId() || hopFace.getId() == faceUsed.getId() ||
76 wouldViolateScope(inFace, interest, hopFace)) {
Vince Lehman8a4c29e2016-07-11 08:49:35 +000077 continue;
78 }
79
Saurab Dulal432be572021-01-26 12:09:29 -060080 FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest.getName(), hopFace.getId());
Vince Lehman8a4c29e2016-07-11 08:49:35 +000081 // If no RTT has been recorded, probe this face
Davide Pesaventoa6f637a2019-08-28 23:23:20 -040082 if (info == nullptr || info->getLastRtt() == FaceInfo::RTT_NO_MEASUREMENT) {
Junxiao Shia6de4292016-07-12 02:08:10 +000083 return &hopFace;
Vince Lehman8a4c29e2016-07-11 08:49:35 +000084 }
85
86 // Add FaceInfo to container sorted by RTT
Davide Pesaventoe4b22382018-06-10 14:37:24 -040087 rankedFaces.insert({info, &hopFace});
Vince Lehman8a4c29e2016-07-11 08:49:35 +000088 }
89
90 if (rankedFaces.empty()) {
91 // No Face to probe
92 return nullptr;
93 }
94
Davide Pesaventoa6f637a2019-08-28 23:23:20 -040095 return chooseFace(rankedFaces);
Vince Lehman8a4c29e2016-07-11 08:49:35 +000096}
97
98bool
Saurab Dulal432be572021-01-26 12:09:29 -060099ProbingModule::isProbingNeeded(const fib::Entry& fibEntry, const Name& interestName)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000100{
101 // Return the probing status flag for a namespace
Saurab Dulal432be572021-01-26 12:09:29 -0600102 NamespaceInfo& info = m_measurements.getOrCreateNamespaceInfo(fibEntry, interestName);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000103
104 // If a first probe has not been scheduled for a namespace
105 if (!info.isFirstProbeScheduled()) {
106 // Schedule first probe between 0 and 5 seconds
Davide Pesaventoa6f637a2019-08-28 23:23:20 -0400107 static std::uniform_int_distribution<> randDist(0, 5000);
108 auto interval = randDist(ndn::random::getRandomNumberEngine());
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000109 scheduleProbe(fibEntry, time::milliseconds(interval));
Davide Pesaventoa6f637a2019-08-28 23:23:20 -0400110 info.setIsFirstProbeScheduled(true);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000111 }
112
113 return info.isProbingDue();
114}
115
116void
Saurab Dulal432be572021-01-26 12:09:29 -0600117ProbingModule::afterForwardingProbe(const fib::Entry& fibEntry, const Name& interestName)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000118{
119 // After probing is done, need to set probing flag to false and
120 // schedule another future probe
Saurab Dulal432be572021-01-26 12:09:29 -0600121 NamespaceInfo& info = m_measurements.getOrCreateNamespaceInfo(fibEntry, interestName);
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000122 info.setIsProbingDue(false);
123
124 scheduleProbe(fibEntry, m_probingInterval);
125}
126
Junxiao Shia6de4292016-07-12 02:08:10 +0000127Face*
Davide Pesaventoa6f637a2019-08-28 23:23:20 -0400128ProbingModule::chooseFace(const FaceInfoFacePairSet& rankedFaces)
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000129{
Davide Pesaventoa6f637a2019-08-28 23:23:20 -0400130 static std::uniform_real_distribution<> randDist;
131 double randomNumber = randDist(ndn::random::getRandomNumberEngine());
132 uint64_t rankSum = (rankedFaces.size() + 1) * rankedFaces.size() / 2;
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000133
134 uint64_t rank = 1;
135 double offset = 0.0;
136
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400137 for (const auto& pair : rankedFaces) {
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000138 double probability = getProbingProbability(rank++, rankSum, rankedFaces.size());
139
140 // Is the random number within the bounds of this face's probability + the previous faces'
141 // probability?
142 //
143 // e.g. (FaceId: 1, p=0.5), (FaceId: 2, p=0.33), (FaceId: 3, p=0.17)
144 // randomNumber = 0.92
145 //
146 // The face with FaceId: 3 should be picked
147 // (0.68 < 0.5 + 0.33 + 0.17) == true
148 //
149 if (randomNumber <= offset + probability) {
150 // Found face to probe
151 return pair.second;
152 }
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000153 offset += probability;
154 }
155
156 // Given a set of Faces, this method should always select a Face to probe
Davide Pesaventoa6f637a2019-08-28 23:23:20 -0400157 NDN_CXX_UNREACHABLE;
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000158}
159
160double
161ProbingModule::getProbingProbability(uint64_t rank, uint64_t rankSum, uint64_t nFaces)
162{
163 // p = n + 1 - j ; n: # faces
164 // ---------
165 // sum(ranks)
166 return static_cast<double>(nFaces + 1 - rank) / rankSum;
167}
168
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500169void
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400170ProbingModule::setProbingInterval(time::milliseconds probingInterval)
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500171{
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400172 if (probingInterval >= MIN_PROBING_INTERVAL) {
173 m_probingInterval = probingInterval;
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500174 }
175 else {
Davide Pesaventoa6f637a2019-08-28 23:23:20 -0400176 NDN_THROW(std::invalid_argument("Probing interval must be >= " +
Davide Pesavento19779d82019-02-14 13:40:04 -0500177 to_string(MIN_PROBING_INTERVAL.count()) + " milliseconds"));
Ashlesh Gawande92e4ea52017-07-19 11:38:12 -0500178 }
179}
180
Vince Lehman8a4c29e2016-07-11 08:49:35 +0000181} // namespace asf
182} // namespace fw
183} // namespace nfd