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