blob: c597e8251421d4cf446be8c272fc6ff8db9c08d6 [file] [log] [blame]
Yanbiao Lid7c96362015-01-30 23:58:24 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Yanbiao Li6db75f02016-01-16 12:25:23 +08003 * Copyright (c) 2014-2016, Regents of the University of California,
Yanbiao Lid7c96362015-01-30 23:58:24 -08004 * 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 "auto-prefix-propagator.hpp"
27#include "core/logger.hpp"
28#include "core/scheduler.hpp"
29#include <ndn-cxx/security/signing-helpers.hpp>
30#include <vector>
31
32namespace nfd {
33namespace rib {
34
35NFD_LOG_INIT("AutoPrefixPropagator");
36
37using ndn::nfd::ControlParameters;
38using ndn::nfd::CommandOptions;
39
40const Name LOCAL_REGISTRATION_PREFIX("/localhost");
41const Name LINK_LOCAL_NFD_PREFIX("/localhop/nfd");
42const name::Component IGNORE_COMMPONENT("nrd");
43const time::seconds PREFIX_PROPAGATION_DEFAULT_REFRESH_INTERVAL = time::seconds(25);
44const time::seconds PREFIX_PROPAGATION_MAX_REFRESH_INTERVAL = time::seconds(600);
45const time::seconds PREFIX_PROPAGATION_DEFAULT_BASE_RETRY_WAIT = time::seconds(50);
46const time::seconds PREFIX_PROPAGATION_DEFAULT_MAX_RETRY_WAIT = time::seconds(3600);
47const uint64_t PREFIX_PROPAGATION_DEFAULT_COST = 15;
48const time::milliseconds PREFIX_PROPAGATION_DEFAULT_TIMEOUT = time::milliseconds(10000);
49
50AutoPrefixPropagator::AutoPrefixPropagator(ndn::nfd::Controller& controller,
51 ndn::KeyChain& keyChain,
52 Rib& rib)
53 : m_nfdController(controller)
54 , m_keyChain(keyChain)
55 , m_rib(rib)
56 , m_refreshInterval(PREFIX_PROPAGATION_DEFAULT_REFRESH_INTERVAL)
57 , m_baseRetryWait(PREFIX_PROPAGATION_DEFAULT_BASE_RETRY_WAIT)
58 , m_maxRetryWait(PREFIX_PROPAGATION_DEFAULT_MAX_RETRY_WAIT)
59 , m_hasConnectedHub(false)
60{
61}
62
63void
64AutoPrefixPropagator::loadConfig(const ConfigSection& configSection)
65{
66 m_refreshInterval = PREFIX_PROPAGATION_DEFAULT_REFRESH_INTERVAL;
67 m_baseRetryWait = PREFIX_PROPAGATION_DEFAULT_BASE_RETRY_WAIT;
68 m_maxRetryWait = PREFIX_PROPAGATION_DEFAULT_MAX_RETRY_WAIT;
69
70 m_controlParameters
71 .setCost(PREFIX_PROPAGATION_DEFAULT_COST)
72 .setOrigin(ndn::nfd::ROUTE_ORIGIN_CLIENT)// set origin to client.
73 .setFaceId(0);// the remote hub will take the input face as the faceId.
74
75 m_commandOptions
76 .setPrefix(LINK_LOCAL_NFD_PREFIX)
77 .setTimeout(PREFIX_PROPAGATION_DEFAULT_TIMEOUT);
78
79 NFD_LOG_INFO("Load auto_prefix_propagate section in rib section");
80
81 for (auto&& i : configSection) {
82 if (i.first == "cost") {
83 m_controlParameters.setCost(i.second.get_value<uint64_t>());
84 }
85 else if (i.first == "timeout") {
86 m_commandOptions.setTimeout(time::milliseconds(i.second.get_value<size_t>()));
87 }
88 else if (i.first == "refresh_interval") {
89 m_refreshInterval = std::min(PREFIX_PROPAGATION_MAX_REFRESH_INTERVAL,
90 time::seconds(i.second.get_value<size_t>()));
91 }
92 else if (i.first == "base_retry_wait") {
93 m_baseRetryWait = time::seconds(i.second.get_value<size_t>());
94 }
95 else if (i.first == "max_retry_wait") {
96 m_maxRetryWait = time::seconds(i.second.get_value<size_t>());
97 }
98 else {
99 BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" + i.first +
100 "\" in \"auto_prefix_propagate\" section"));
101 }
102 }
103}
104
105void
106AutoPrefixPropagator::enable()
107{
108 m_afterInsertConnection =
109 m_rib.afterInsertEntry.connect(bind(&AutoPrefixPropagator::afterInsertRibEntry, this, _1));
110 m_afterEraseConnection =
111 m_rib.afterEraseEntry.connect(bind(&AutoPrefixPropagator::afterEraseRibEntry, this, _1));
112}
113
114void
115AutoPrefixPropagator::disable()
116{
117 m_afterInsertConnection.disconnect();
118 m_afterEraseConnection.disconnect();
119}
120
121AutoPrefixPropagator::PrefixPropagationParameters
122AutoPrefixPropagator::getPrefixPropagationParameters(const Name& localRibPrefix)
123{
124 // get all identities from the KeyChain
125 std::vector<Name> identities;
126 m_keyChain.getAllIdentities(identities, false); // get all except the default
127 identities.push_back(m_keyChain.getDefaultIdentity()); // get the default
128
129 // shortest prefix matching to all identies.
130 Name propagatedPrefix, signingIdentity;
131 bool isFound = false;
132 for (auto&& i : identities) {
133 Name prefix = !i.empty() && IGNORE_COMMPONENT == i.at(-1) ? i.getPrefix(-1) : i;
134 if (prefix.isPrefixOf(localRibPrefix) && (!isFound || i.size() < signingIdentity.size())) {
135 isFound = true;
136 propagatedPrefix = prefix;
137 signingIdentity = i;
138 }
139 }
140
141 PrefixPropagationParameters propagateParameters;
142 if (!isFound) {
143 propagateParameters.isValid = false;
144 }
145 else {
146 propagateParameters.isValid = true;
147 propagateParameters.parameters = m_controlParameters;
148 propagateParameters.options = m_commandOptions;
149 propagateParameters.parameters.setName(propagatedPrefix);
150 propagateParameters.options.setSigningInfo(signingByIdentity(signingIdentity));
151 }
152
153 return propagateParameters;
154}
155
156void
157AutoPrefixPropagator::afterInsertRibEntry(const Name& prefix)
158{
159 if (LOCAL_REGISTRATION_PREFIX.isPrefixOf(prefix)) {
160 NFD_LOG_INFO("local registration only for " << prefix);
161 return;
162 }
163
164 if (prefix == LINK_LOCAL_NFD_PREFIX) {
165 NFD_LOG_INFO("this is a prefix registered by some hub: " << prefix);
166
167 m_hasConnectedHub = true;
168 return afterHubConnect();
169 }
170
171 auto propagateParameters = getPrefixPropagationParameters(prefix);
172 if (!propagateParameters.isValid) {
173 NFD_LOG_INFO("no signing identity available for: " << prefix);
174 return;
175 }
176
177 auto entryIt = m_propagatedEntries.find(propagateParameters.parameters.getName());
178 if (entryIt != m_propagatedEntries.end()) {
Yanbiao Li6db75f02016-01-16 12:25:23 +0800179 // in addition to PROPAGATED and PROPAGATE_FAIL, the state may also be NEW,
180 // if its propagation was suspended because there was no connectivity to the Hub.
Yanbiao Lid7c96362015-01-30 23:58:24 -0800181 NFD_LOG_INFO("prefix has already been propagated: "
182 << propagateParameters.parameters.getName());
183 return;
184 }
185
186 afterRibInsert(propagateParameters.parameters, propagateParameters.options);
187}
188
189void
190AutoPrefixPropagator::afterEraseRibEntry(const Name& prefix)
191{
192 if (LOCAL_REGISTRATION_PREFIX.isPrefixOf(prefix)) {
193 NFD_LOG_INFO("local unregistration only for " << prefix);
194 return;
195 }
196
197 if (prefix == LINK_LOCAL_NFD_PREFIX) {
198 NFD_LOG_INFO("disconnected to hub with prefix: " << prefix);
199
200 m_hasConnectedHub = false;
201 return afterHubDisconnect();
202 }
203
204 auto propagateParameters = getPrefixPropagationParameters(prefix);
205 if (!propagateParameters.isValid) {
206 NFD_LOG_INFO("no signing identity available for: " << prefix);
207 return;
208 }
209
210 auto entryIt = m_propagatedEntries.find(propagateParameters.parameters.getName());
211 if (entryIt == m_propagatedEntries.end()) {
212 NFD_LOG_INFO("prefix has not been propagated yet: "
213 << propagateParameters.parameters.getName());
214 return;
215 }
216
217 for (auto&& ribTableEntry : m_rib) {
218 if (propagateParameters.parameters.getName().isPrefixOf(ribTableEntry.first) &&
219 propagateParameters.options.getSigningInfo().getSignerName() ==
220 getPrefixPropagationParameters(ribTableEntry.first)
221 .options.getSigningInfo().getSignerName()) {
222 NFD_LOG_INFO("should be kept for another RIB entry: " << ribTableEntry.first);
223 return;
224 }
225 }
226
227 afterRibErase(propagateParameters.parameters.unsetCost(), propagateParameters.options);
228}
229
230bool
231AutoPrefixPropagator::doesCurrentPropagatedPrefixWork(const Name& prefix)
232{
233 auto propagateParameters = getPrefixPropagationParameters(prefix);
234 if (!propagateParameters.isValid) {
235 // no identity can sign the input prefix
236 return false;
237 }
238
239 // there is at least one identity can sign the input prefix, so the prefix selected for
240 // propagation (i.e., propagateParameters.parameters.getName()) must be a prefix of the input
241 // prefix. Namely it's either equal to the input prefix or a better choice.
242 return propagateParameters.parameters.getName().size() == prefix.size();
243}
244
245void
246AutoPrefixPropagator::redoPropagation(PropagatedEntryIt entryIt,
247 const ControlParameters& parameters,
248 const CommandOptions& options,
249 time::seconds retryWaitTime)
250{
251 if (doesCurrentPropagatedPrefixWork(parameters.getName())) {
252 // PROPAGATED / PROPAGATE_FAIL --> PROPAGATING
253 entryIt->second.startPropagation();
254 return startPropagation(parameters, options, retryWaitTime);
255 }
256
257 NFD_LOG_INFO("current propagated prefix does not work any more");
258 m_propagatedEntries.erase(entryIt);
259
260 // re-handle all locally RIB entries that can be covered by this propagated prefix
261 for (auto&& ribTableEntry : m_rib) {
262 if (parameters.getName().isPrefixOf(ribTableEntry.first)) {
263 afterInsertRibEntry(ribTableEntry.first);
264 }
265 }
266}
267
268void
269AutoPrefixPropagator::startPropagation(const ControlParameters& parameters,
270 const CommandOptions& options,
271 time::seconds retryWaitTime)
272{
273 NFD_LOG_TRACE("start propagate " << parameters.getName());
274
275 ndn::Scheduler::Event refreshEvent =
276 bind(&AutoPrefixPropagator::onRefreshTimer, this, parameters, options);
277 ndn::Scheduler::Event retryEvent =
278 bind(&AutoPrefixPropagator::onRetryTimer, this, parameters, options,
279 std::min(m_maxRetryWait, retryWaitTime * 2));
280
281 m_nfdController.start<ndn::nfd::RibRegisterCommand>(
282 parameters,
283 bind(&AutoPrefixPropagator::afterPropagateSucceed, this, parameters, options, refreshEvent),
284 bind(&AutoPrefixPropagator::afterPropagateFail,
Junxiao Shi29b41282016-08-22 03:47:02 +0000285 this, _1, parameters, options, retryWaitTime, retryEvent),
Yanbiao Lid7c96362015-01-30 23:58:24 -0800286 options);
287}
288
289void
290AutoPrefixPropagator::startRevocation(const ControlParameters& parameters,
291 const CommandOptions& options,
292 time::seconds retryWaitTime)
293{
294 NFD_LOG_INFO("start revoke propagation of " << parameters.getName());
295
296 m_nfdController.start<ndn::nfd::RibUnregisterCommand>(
297 parameters,
298 bind(&AutoPrefixPropagator::afterRevokeSucceed, this, parameters, options, retryWaitTime),
Junxiao Shi29b41282016-08-22 03:47:02 +0000299 bind(&AutoPrefixPropagator::afterRevokeFail, this, _1, parameters, options),
Yanbiao Lid7c96362015-01-30 23:58:24 -0800300 options);
301}
302
303void
304AutoPrefixPropagator::afterRibInsert(const ControlParameters& parameters,
305 const CommandOptions& options)
306{
307 BOOST_ASSERT(m_propagatedEntries.find(parameters.getName()) == m_propagatedEntries.end());
308
309 // keep valid entries although there is no connectivity to hub
310 auto& entry = m_propagatedEntries[parameters.getName()]
311 .setSigningIdentity(options.getSigningInfo().getSignerName());
312
313 if (!m_hasConnectedHub) {
314 NFD_LOG_INFO("no hub connected to propagate " << parameters.getName());
315 return;
316 }
317
318 // NEW --> PROPAGATING
319 entry.startPropagation();
320 startPropagation(parameters, options, m_baseRetryWait);
321}
322
323void
324AutoPrefixPropagator::afterRibErase(const ControlParameters& parameters,
325 const CommandOptions& options)
326{
327 auto entryIt = m_propagatedEntries.find(parameters.getName());
328 BOOST_ASSERT(entryIt != m_propagatedEntries.end());
329
330 bool hasPropagationSucceeded = entryIt->second.isPropagated();
331
332 // --> "RELEASED"
333 m_propagatedEntries.erase(entryIt);
334
335 if (!m_hasConnectedHub) {
336 NFD_LOG_INFO("no hub connected to revoke propagation of " << parameters.getName());
337 return;
338 }
339
340 if (!hasPropagationSucceeded) {
341 NFD_LOG_INFO("propagation has not succeeded: " << parameters.getName());
342 return;
343 }
344
345 startRevocation(parameters, options, m_baseRetryWait);
346}
347
348void
349AutoPrefixPropagator::afterHubConnect()
350{
351 NFD_LOG_INFO("redo " << m_propagatedEntries.size()
352 << " propagations when new Hub connectivity is built.");
353
354 std::vector<PropagatedEntryIt> regEntryIterators;
355 for (auto it = m_propagatedEntries.begin() ; it != m_propagatedEntries.end() ; it ++) {
356 BOOST_ASSERT(it->second.isNew());
357 regEntryIterators.push_back(it);
358 }
359
360 for (auto&& it : regEntryIterators) {
361 auto parameters = m_controlParameters;
362 auto options = m_commandOptions;
363
364 redoPropagation(it,
365 parameters.setName(it->first),
366 options.setSigningInfo(signingByIdentity(it->second.getSigningIdentity())),
367 m_baseRetryWait);
368 }
369}
370
371void
372AutoPrefixPropagator::afterHubDisconnect()
373{
374 for (auto&& entry : m_propagatedEntries) {
375 // --> NEW
376 BOOST_ASSERT(!entry.second.isNew());
377 entry.second.initialize();
378 }
379}
380
381void
382AutoPrefixPropagator::afterPropagateSucceed(const ControlParameters& parameters,
383 const CommandOptions& options,
384 const ndn::Scheduler::Event& refreshEvent)
385{
386 NFD_LOG_TRACE("success to propagate " << parameters.getName());
387
388 auto entryIt = m_propagatedEntries.find(parameters.getName());
389 if (entryIt == m_propagatedEntries.end()) {
390 // propagation should be revoked if this entry has been erased (i.e., be in RELEASED state)
391 NFD_LOG_DEBUG("Already erased!");
392 ControlParameters newParameters = parameters;
393 return startRevocation(newParameters.unsetCost(), options, m_baseRetryWait);
394 }
395
396 // PROPAGATING --> PROPAGATED
397 BOOST_ASSERT(entryIt->second.isPropagating());
398 entryIt->second.succeed(scheduler::schedule(m_refreshInterval, refreshEvent));
399}
400
401void
Junxiao Shi29b41282016-08-22 03:47:02 +0000402AutoPrefixPropagator::afterPropagateFail(const ndn::nfd::ControlResponse& response,
Yanbiao Lid7c96362015-01-30 23:58:24 -0800403 const ControlParameters& parameters,
404 const CommandOptions& options,
405 time::seconds retryWaitTime,
406 const ndn::Scheduler::Event& retryEvent)
407{
408 NFD_LOG_TRACE("fail to propagate " << parameters.getName()
Junxiao Shi29b41282016-08-22 03:47:02 +0000409 << "\n\t reason:" << response.getText()
Yanbiao Lid7c96362015-01-30 23:58:24 -0800410 << "\n\t retry wait time: " << retryWaitTime);
411
412 auto entryIt = m_propagatedEntries.find(parameters.getName());
413 if (entryIt == m_propagatedEntries.end()) {
414 // current state is RELEASED
415 return;
416 }
417
418 // PROPAGATING --> PROPAGATE_FAIL
419 BOOST_ASSERT(entryIt->second.isPropagating());
420 entryIt->second.fail(scheduler::schedule(retryWaitTime, retryEvent));
421}
422
423void
424AutoPrefixPropagator::afterRevokeSucceed(const ControlParameters& parameters,
425 const CommandOptions& options,
426 time::seconds retryWaitTime)
427{
428 NFD_LOG_TRACE("success to revoke propagation of " << parameters.getName());
429
430 auto entryIt = m_propagatedEntries.find(parameters.getName());
431 if (m_propagatedEntries.end() != entryIt && !entryIt->second.isPropagateFail()) {
432 // if is not RELEASED or PROPAGATE_FAIL
433 NFD_LOG_DEBUG("propagated entry still exists");
434
435 // PROPAGATING / PROPAGATED --> PROPAGATING
436 BOOST_ASSERT(!entryIt->second.isNew());
437 entryIt->second.startPropagation();
438
439 ControlParameters newParameters = parameters;
440 startPropagation(newParameters.setCost(m_controlParameters.getCost()), options, retryWaitTime);
441 }
442}
443
444void
Junxiao Shi29b41282016-08-22 03:47:02 +0000445AutoPrefixPropagator::afterRevokeFail(const ndn::nfd::ControlResponse& response,
446 const ControlParameters& parameters,
447 const CommandOptions& options)
Yanbiao Lid7c96362015-01-30 23:58:24 -0800448{
449 NFD_LOG_INFO("fail to revoke the propagation of " << parameters.getName()
Junxiao Shi29b41282016-08-22 03:47:02 +0000450 << "\n\t reason:" << response.getText());
Yanbiao Lid7c96362015-01-30 23:58:24 -0800451}
452
453void
454AutoPrefixPropagator::onRefreshTimer(const ControlParameters& parameters,
455 const CommandOptions& options)
456{
457 auto entryIt = m_propagatedEntries.find(parameters.getName());
458 BOOST_ASSERT(entryIt != m_propagatedEntries.end() && entryIt->second.isPropagated());
459 redoPropagation(entryIt, parameters, options, m_baseRetryWait);
460}
461
462void
463AutoPrefixPropagator::onRetryTimer(const ControlParameters& parameters,
464 const CommandOptions& options,
465 time::seconds retryWaitTime)
466{
467 auto entryIt = m_propagatedEntries.find(parameters.getName());
468 BOOST_ASSERT(entryIt != m_propagatedEntries.end() && entryIt->second.isPropagateFail());
469 redoPropagation(entryIt, parameters, options, retryWaitTime);
470}
471
472} // namespace rib
473} // namespace nfd