blob: 1a2eca212f6f608426e79b28cb23e056b476469b [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-measurements.hpp"
27
28namespace nfd {
29namespace fw {
30namespace asf {
31
32NFD_LOG_INIT("AsfMeasurements");
33
34const RttStats::Rtt RttStats::RTT_TIMEOUT(-1.0);
35const RttStats::Rtt RttStats::RTT_NO_MEASUREMENT(0.0);
36const double RttStats::ALPHA = 0.125;
37
38RttStats::RttStats()
39 : m_srtt(RTT_NO_MEASUREMENT)
40 , m_rtt(RTT_NO_MEASUREMENT)
41{
42}
43
44void
45RttStats::addRttMeasurement(RttEstimator::Duration& durationRtt)
46{
47 m_rtt = static_cast<RttStats::Rtt>(durationRtt.count());
48
49 m_rttEstimator.addMeasurement(durationRtt);
50
51 m_srtt = computeSrtt(m_srtt, m_rtt);
52}
53
54RttStats::Rtt
55RttStats::computeSrtt(Rtt previousSrtt, Rtt currentRtt)
56{
57 if (previousSrtt == RTT_NO_MEASUREMENT) {
58 return currentRtt;
59 }
60
61 return Rtt(ALPHA * currentRtt + (1 - ALPHA) * previousSrtt);
62}
63
64////////////////////////////////////////////////////////////////////////////////
65////////////////////////////////////////////////////////////////////////////////
66
67FaceInfo::FaceInfo()
68 : m_isTimeoutScheduled(false)
69{
70}
71
72FaceInfo::~FaceInfo()
73{
74 cancelTimeoutEvent();
75 scheduler::cancel(m_measurementExpirationId);
76}
77
78void
79FaceInfo::setTimeoutEvent(const scheduler::EventId& id, const ndn::Name& interestName)
80{
81 if (!m_isTimeoutScheduled) {
82 m_timeoutEventId = id;
83 m_isTimeoutScheduled = true;
84 m_lastInterestName = interestName;
85 }
86 else {
87 BOOST_THROW_EXCEPTION(FaceInfo::Error("Tried to schedule a timeout for a face that already has a timeout scheduled."));
88 }
89}
90
91void
92FaceInfo::cancelTimeoutEvent()
93{
94 scheduler::cancel(m_timeoutEventId);
95 m_isTimeoutScheduled = false;
96}
97
98void
99FaceInfo::cancelTimeoutEvent(const ndn::Name& prefix)
100{
101 if (isTimeoutScheduled() && doesNameMatchLastInterest(prefix)) {
102 cancelTimeoutEvent();
103 }
104}
105
106bool
107FaceInfo::doesNameMatchLastInterest(const ndn::Name& name)
108{
109 return m_lastInterestName.isPrefixOf(name);
110}
111
112void
113FaceInfo::recordRtt(const shared_ptr<pit::Entry> pitEntry, const Face& inFace)
114{
115 // Calculate RTT
116 pit::OutRecordCollection::const_iterator outRecord = pitEntry->getOutRecord(inFace);
117 time::steady_clock::Duration steadyRtt = time::steady_clock::now() - outRecord->getLastRenewed();
118 RttEstimator::Duration durationRtt = time::duration_cast<RttEstimator::Duration>(steadyRtt);
119
120 m_rttStats.addRttMeasurement(durationRtt);
121
122 NFD_LOG_TRACE("Recording RTT for FaceId: " << inFace.getId()
123 << " RTT: " << m_rttStats.getRtt()
124 << " SRTT: " << m_rttStats.getSrtt());
125}
126
127void
128FaceInfo::recordTimeout(const ndn::Name& interestName)
129{
130 m_rttStats.recordTimeout();
131 cancelTimeoutEvent(interestName);
132}
133
134////////////////////////////////////////////////////////////////////////////////
135////////////////////////////////////////////////////////////////////////////////
136
137NamespaceInfo::NamespaceInfo()
138 : m_isProbingDue(false)
139 , m_hasFirstProbeBeenScheduled(false)
140{
141}
142
143FaceInfo*
144NamespaceInfo::getFaceInfo(const fib::Entry& fibEntry, const Face& face)
145{
146 FaceInfoTable::iterator it = m_fit.find(face.getId());
147
148 if (it != m_fit.end()) {
149 return &it->second;
150 }
151 else {
152 return nullptr;
153 }
154}
155
156FaceInfo&
157NamespaceInfo::getOrCreateFaceInfo(const fib::Entry& fibEntry, const Face& face)
158{
159 FaceInfoTable::iterator it = m_fit.find(face.getId());
160
161 FaceInfo* info = nullptr;
162
163 if (it == m_fit.end()) {
164 const auto& pair = m_fit.insert(std::make_pair(face.getId(), FaceInfo()));
165 info = &pair.first->second;
166
167 extendFaceInfoLifetime(*info, face);
168 }
169 else {
170 info = &it->second;
171 }
172
173 return *info;
174}
175
176void
177NamespaceInfo::expireFaceInfo(nfd::face::FaceId faceId)
178{
179 m_fit.erase(faceId);
180}
181
182void
183NamespaceInfo::extendFaceInfoLifetime(FaceInfo& info, const Face& face)
184{
185 // Cancel previous expiration
186 scheduler::cancel(info.getMeasurementExpirationEventId());
187
188 // Refresh measurement
189 scheduler::EventId id = scheduler::schedule(AsfMeasurements::MEASUREMENTS_LIFETIME,
190 bind(&NamespaceInfo::expireFaceInfo, this, face.getId()));
191
192 info.setMeasurementExpirationEventId(id);
193}
194
195////////////////////////////////////////////////////////////////////////////////
196////////////////////////////////////////////////////////////////////////////////
197
198constexpr time::microseconds AsfMeasurements::MEASUREMENTS_LIFETIME;
199
200AsfMeasurements::AsfMeasurements(MeasurementsAccessor& measurements)
201 : m_measurements(measurements)
202{
203}
204
205FaceInfo*
206AsfMeasurements::getFaceInfo(const fib::Entry& fibEntry, const ndn::Interest& interest, const Face& face)
207{
208 NamespaceInfo& info = getOrCreateNamespaceInfo(fibEntry, interest);
209 return info.getFaceInfo(fibEntry, face);
210}
211
212FaceInfo&
213AsfMeasurements::getOrCreateFaceInfo(const fib::Entry& fibEntry, const ndn::Interest& interest, const Face& face)
214{
215 NamespaceInfo& info = getOrCreateNamespaceInfo(fibEntry, interest);
216 return info.getOrCreateFaceInfo(fibEntry, face);
217}
218
219shared_ptr<NamespaceInfo>
220AsfMeasurements::getNamespaceInfo(const ndn::Name& prefix)
221{
222 shared_ptr<measurements::Entry> me = m_measurements.findLongestPrefixMatch(prefix);
223
224 if (me == nullptr) {
225 return nullptr;
226 }
227
228 // Set or update entry lifetime
229 extendLifetime(me);
230
231 shared_ptr<NamespaceInfo> info = me->getOrCreateStrategyInfo<NamespaceInfo>();
232 BOOST_ASSERT(info != nullptr);
233
234 return info;
235}
236
237NamespaceInfo&
238AsfMeasurements::getOrCreateNamespaceInfo(const fib::Entry& fibEntry, const ndn::Interest& interest)
239{
240 shared_ptr<measurements::Entry> me = m_measurements.get(fibEntry);
241
242 // If the FIB entry is not under the strategy's namespace, find a part of the prefix
243 // that falls under the strategy's namespace
244 for (size_t prefixLen = fibEntry.getPrefix().size() + 1;
245 me == nullptr && prefixLen <= interest.getName().size(); ++prefixLen) {
246 me = m_measurements.get(interest.getName().getPrefix(prefixLen));
247 }
248
249 // Either the FIB entry or the Interest's name must be under this strategy's namespace
250 BOOST_ASSERT(me != nullptr);
251
252 // Set or update entry lifetime
253 extendLifetime(me);
254
255 shared_ptr<NamespaceInfo> info = me->getOrCreateStrategyInfo<NamespaceInfo>();
256 BOOST_ASSERT(info != nullptr);
257
258 return *info;
259}
260
261void
262AsfMeasurements::extendLifetime(shared_ptr<measurements::Entry> me)
263{
264 if (me != nullptr) {
265 m_measurements.extendLifetime(*me, MEASUREMENTS_LIFETIME);
266 }
267}
268
269} // namespace asf
270} // namespace fw
271} // namespace nfd