blob: a03302a939253b25bbb97669a07e00c1a5741732 [file] [log] [blame]
Yanbiao Lid7c96362015-01-30 23:58:24 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesaventoa3148082018-04-12 18:21:54 -04002/*
3 * Copyright (c) 2014-2018, 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"
Davide Pesaventoa3148082018-04-12 18:21:54 -040028
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>
Yanbiao Lid7c96362015-01-30 23:58:24 -080033
34namespace nfd {
35namespace rib {
36
Davide Pesaventoa3148082018-04-12 18:21:54 -040037NFD_LOG_INIT(AutoPrefixPropagator);
Yanbiao Lid7c96362015-01-30 23:58:24 -080038
39using ndn::nfd::ControlParameters;
40using ndn::nfd::CommandOptions;
Davide Pesaventoe1bdc082018-10-11 21:20:23 -040041using ndn::util::scheduler::EventCallback;
Yanbiao Lid7c96362015-01-30 23:58:24 -080042
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,
Davide Pesaventoe1bdc082018-10-11 21:20:23 -040055 ndn::util::Scheduler& scheduler,
Yanbiao Lid7c96362015-01-30 23:58:24 -080056 Rib& rib)
57 : m_nfdController(controller)
58 , m_keyChain(keyChain)
Davide Pesaventoe1bdc082018-10-11 21:20:23 -040059 , m_scheduler(scheduler)
Yanbiao Lid7c96362015-01-30 23:58:24 -080060 , m_rib(rib)
61 , m_refreshInterval(PREFIX_PROPAGATION_DEFAULT_REFRESH_INTERVAL)
62 , m_baseRetryWait(PREFIX_PROPAGATION_DEFAULT_BASE_RETRY_WAIT)
63 , m_maxRetryWait(PREFIX_PROPAGATION_DEFAULT_MAX_RETRY_WAIT)
64 , m_hasConnectedHub(false)
65{
66}
67
68void
69AutoPrefixPropagator::loadConfig(const ConfigSection& configSection)
70{
71 m_refreshInterval = PREFIX_PROPAGATION_DEFAULT_REFRESH_INTERVAL;
72 m_baseRetryWait = PREFIX_PROPAGATION_DEFAULT_BASE_RETRY_WAIT;
73 m_maxRetryWait = PREFIX_PROPAGATION_DEFAULT_MAX_RETRY_WAIT;
74
75 m_controlParameters
76 .setCost(PREFIX_PROPAGATION_DEFAULT_COST)
77 .setOrigin(ndn::nfd::ROUTE_ORIGIN_CLIENT)// set origin to client.
78 .setFaceId(0);// the remote hub will take the input face as the faceId.
79
80 m_commandOptions
81 .setPrefix(LINK_LOCAL_NFD_PREFIX)
82 .setTimeout(PREFIX_PROPAGATION_DEFAULT_TIMEOUT);
83
84 NFD_LOG_INFO("Load auto_prefix_propagate section in rib section");
85
86 for (auto&& i : configSection) {
87 if (i.first == "cost") {
88 m_controlParameters.setCost(i.second.get_value<uint64_t>());
89 }
90 else if (i.first == "timeout") {
91 m_commandOptions.setTimeout(time::milliseconds(i.second.get_value<size_t>()));
92 }
93 else if (i.first == "refresh_interval") {
94 m_refreshInterval = std::min(PREFIX_PROPAGATION_MAX_REFRESH_INTERVAL,
95 time::seconds(i.second.get_value<size_t>()));
96 }
97 else if (i.first == "base_retry_wait") {
98 m_baseRetryWait = time::seconds(i.second.get_value<size_t>());
99 }
100 else if (i.first == "max_retry_wait") {
101 m_maxRetryWait = time::seconds(i.second.get_value<size_t>());
102 }
103 else {
104 BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" + i.first +
105 "\" in \"auto_prefix_propagate\" section"));
106 }
107 }
108}
109
110void
111AutoPrefixPropagator::enable()
112{
113 m_afterInsertConnection =
114 m_rib.afterInsertEntry.connect(bind(&AutoPrefixPropagator::afterInsertRibEntry, this, _1));
115 m_afterEraseConnection =
116 m_rib.afterEraseEntry.connect(bind(&AutoPrefixPropagator::afterEraseRibEntry, this, _1));
117}
118
119void
120AutoPrefixPropagator::disable()
121{
122 m_afterInsertConnection.disconnect();
123 m_afterEraseConnection.disconnect();
124}
125
126AutoPrefixPropagator::PrefixPropagationParameters
127AutoPrefixPropagator::getPrefixPropagationParameters(const Name& localRibPrefix)
128{
Yanbiao Lid7c96362015-01-30 23:58:24 -0800129 // shortest prefix matching to all identies.
Junxiao Shi16a3adf2017-05-26 17:38:51 +0000130 Name propagatedPrefix;
131 ndn::security::pib::Identity signingIdentity;
Yanbiao Lid7c96362015-01-30 23:58:24 -0800132 bool isFound = false;
Junxiao Shi16a3adf2017-05-26 17:38:51 +0000133 for (auto&& identity : m_keyChain.getPib().getIdentities()) {
134 Name idName = identity.getName();
135 Name prefix = !idName.empty() && IGNORE_COMMPONENT == idName.at(-1) ?
136 idName.getPrefix(-1) : idName;
137 if (prefix.isPrefixOf(localRibPrefix) && (!isFound || prefix.size() < propagatedPrefix.size())) {
Yanbiao Lid7c96362015-01-30 23:58:24 -0800138 isFound = true;
139 propagatedPrefix = prefix;
Junxiao Shi16a3adf2017-05-26 17:38:51 +0000140 signingIdentity = identity;
Yanbiao Lid7c96362015-01-30 23:58:24 -0800141 }
142 }
143
144 PrefixPropagationParameters propagateParameters;
145 if (!isFound) {
146 propagateParameters.isValid = false;
147 }
148 else {
149 propagateParameters.isValid = true;
150 propagateParameters.parameters = m_controlParameters;
151 propagateParameters.options = m_commandOptions;
152 propagateParameters.parameters.setName(propagatedPrefix);
Junxiao Shi16a3adf2017-05-26 17:38:51 +0000153 propagateParameters.options.setSigningInfo(ndn::security::signingByIdentity(signingIdentity));
Yanbiao Lid7c96362015-01-30 23:58:24 -0800154 }
155
156 return propagateParameters;
157}
158
159void
160AutoPrefixPropagator::afterInsertRibEntry(const Name& prefix)
161{
162 if (LOCAL_REGISTRATION_PREFIX.isPrefixOf(prefix)) {
163 NFD_LOG_INFO("local registration only for " << prefix);
164 return;
165 }
166
167 if (prefix == LINK_LOCAL_NFD_PREFIX) {
168 NFD_LOG_INFO("this is a prefix registered by some hub: " << prefix);
169
170 m_hasConnectedHub = true;
171 return afterHubConnect();
172 }
173
174 auto propagateParameters = getPrefixPropagationParameters(prefix);
175 if (!propagateParameters.isValid) {
176 NFD_LOG_INFO("no signing identity available for: " << prefix);
177 return;
178 }
179
180 auto entryIt = m_propagatedEntries.find(propagateParameters.parameters.getName());
181 if (entryIt != m_propagatedEntries.end()) {
Yanbiao Li6db75f02016-01-16 12:25:23 +0800182 // in addition to PROPAGATED and PROPAGATE_FAIL, the state may also be NEW,
Yanbiao Lif32ca892017-05-31 10:08:07 +0800183 // if there is no hub connected to propagate this prefix.
184 if (entryIt->second.isNew()) {
185 NFD_LOG_INFO("no hub connected to propagate "
186 << propagateParameters.parameters.getName());
187 }
188 else {
189 NFD_LOG_INFO("prefix has already been propagated: "
190 << propagateParameters.parameters.getName());
191 }
Yanbiao Lid7c96362015-01-30 23:58:24 -0800192 return;
193 }
194
195 afterRibInsert(propagateParameters.parameters, propagateParameters.options);
196}
197
198void
199AutoPrefixPropagator::afterEraseRibEntry(const Name& prefix)
200{
201 if (LOCAL_REGISTRATION_PREFIX.isPrefixOf(prefix)) {
202 NFD_LOG_INFO("local unregistration only for " << prefix);
203 return;
204 }
205
206 if (prefix == LINK_LOCAL_NFD_PREFIX) {
207 NFD_LOG_INFO("disconnected to hub with prefix: " << prefix);
208
209 m_hasConnectedHub = false;
210 return afterHubDisconnect();
211 }
212
213 auto propagateParameters = getPrefixPropagationParameters(prefix);
214 if (!propagateParameters.isValid) {
215 NFD_LOG_INFO("no signing identity available for: " << prefix);
216 return;
217 }
218
219 auto entryIt = m_propagatedEntries.find(propagateParameters.parameters.getName());
220 if (entryIt == m_propagatedEntries.end()) {
221 NFD_LOG_INFO("prefix has not been propagated yet: "
222 << propagateParameters.parameters.getName());
223 return;
224 }
225
226 for (auto&& ribTableEntry : m_rib) {
227 if (propagateParameters.parameters.getName().isPrefixOf(ribTableEntry.first) &&
228 propagateParameters.options.getSigningInfo().getSignerName() ==
229 getPrefixPropagationParameters(ribTableEntry.first)
230 .options.getSigningInfo().getSignerName()) {
231 NFD_LOG_INFO("should be kept for another RIB entry: " << ribTableEntry.first);
232 return;
233 }
234 }
235
236 afterRibErase(propagateParameters.parameters.unsetCost(), propagateParameters.options);
237}
238
239bool
240AutoPrefixPropagator::doesCurrentPropagatedPrefixWork(const Name& prefix)
241{
242 auto propagateParameters = getPrefixPropagationParameters(prefix);
243 if (!propagateParameters.isValid) {
244 // no identity can sign the input prefix
245 return false;
246 }
247
248 // there is at least one identity can sign the input prefix, so the prefix selected for
249 // propagation (i.e., propagateParameters.parameters.getName()) must be a prefix of the input
250 // prefix. Namely it's either equal to the input prefix or a better choice.
251 return propagateParameters.parameters.getName().size() == prefix.size();
252}
253
254void
255AutoPrefixPropagator::redoPropagation(PropagatedEntryIt entryIt,
256 const ControlParameters& parameters,
257 const CommandOptions& options,
258 time::seconds retryWaitTime)
259{
260 if (doesCurrentPropagatedPrefixWork(parameters.getName())) {
261 // PROPAGATED / PROPAGATE_FAIL --> PROPAGATING
262 entryIt->second.startPropagation();
Yanbiao Li5ad19fe2016-09-03 07:16:46 +0000263 return advertise(parameters, options, retryWaitTime);
Yanbiao Lid7c96362015-01-30 23:58:24 -0800264 }
265
266 NFD_LOG_INFO("current propagated prefix does not work any more");
267 m_propagatedEntries.erase(entryIt);
268
269 // re-handle all locally RIB entries that can be covered by this propagated prefix
270 for (auto&& ribTableEntry : m_rib) {
271 if (parameters.getName().isPrefixOf(ribTableEntry.first)) {
272 afterInsertRibEntry(ribTableEntry.first);
273 }
274 }
275}
276
277void
Yanbiao Li5ad19fe2016-09-03 07:16:46 +0000278AutoPrefixPropagator::advertise(const ControlParameters& parameters,
279 const CommandOptions& options,
280 time::seconds retryWaitTime)
Yanbiao Lid7c96362015-01-30 23:58:24 -0800281{
Yanbiao Li5ad19fe2016-09-03 07:16:46 +0000282 NFD_LOG_INFO("advertise " << parameters.getName());
Yanbiao Lid7c96362015-01-30 23:58:24 -0800283
Davide Pesaventoe1bdc082018-10-11 21:20:23 -0400284 EventCallback refreshEvent =
Yanbiao Lid7c96362015-01-30 23:58:24 -0800285 bind(&AutoPrefixPropagator::onRefreshTimer, this, parameters, options);
Davide Pesaventoe1bdc082018-10-11 21:20:23 -0400286 EventCallback retryEvent =
Yanbiao Lid7c96362015-01-30 23:58:24 -0800287 bind(&AutoPrefixPropagator::onRetryTimer, this, parameters, options,
288 std::min(m_maxRetryWait, retryWaitTime * 2));
289
290 m_nfdController.start<ndn::nfd::RibRegisterCommand>(
291 parameters,
292 bind(&AutoPrefixPropagator::afterPropagateSucceed, this, parameters, options, refreshEvent),
293 bind(&AutoPrefixPropagator::afterPropagateFail,
Junxiao Shi29b41282016-08-22 03:47:02 +0000294 this, _1, parameters, options, retryWaitTime, retryEvent),
Yanbiao Lid7c96362015-01-30 23:58:24 -0800295 options);
296}
297
298void
Yanbiao Li5ad19fe2016-09-03 07:16:46 +0000299AutoPrefixPropagator::withdraw(const ControlParameters& parameters,
300 const CommandOptions& options,
301 time::seconds retryWaitTime)
Yanbiao Lid7c96362015-01-30 23:58:24 -0800302{
Yanbiao Li5ad19fe2016-09-03 07:16:46 +0000303 NFD_LOG_INFO("withdraw " << parameters.getName());
Yanbiao Lid7c96362015-01-30 23:58:24 -0800304
305 m_nfdController.start<ndn::nfd::RibUnregisterCommand>(
306 parameters,
307 bind(&AutoPrefixPropagator::afterRevokeSucceed, this, parameters, options, retryWaitTime),
Junxiao Shi29b41282016-08-22 03:47:02 +0000308 bind(&AutoPrefixPropagator::afterRevokeFail, this, _1, parameters, options),
Yanbiao Lid7c96362015-01-30 23:58:24 -0800309 options);
310}
311
312void
313AutoPrefixPropagator::afterRibInsert(const ControlParameters& parameters,
314 const CommandOptions& options)
315{
316 BOOST_ASSERT(m_propagatedEntries.find(parameters.getName()) == m_propagatedEntries.end());
317
318 // keep valid entries although there is no connectivity to hub
319 auto& entry = m_propagatedEntries[parameters.getName()]
320 .setSigningIdentity(options.getSigningInfo().getSignerName());
321
322 if (!m_hasConnectedHub) {
323 NFD_LOG_INFO("no hub connected to propagate " << parameters.getName());
324 return;
325 }
326
327 // NEW --> PROPAGATING
328 entry.startPropagation();
Yanbiao Li5ad19fe2016-09-03 07:16:46 +0000329 advertise(parameters, options, m_baseRetryWait);
Yanbiao Lid7c96362015-01-30 23:58:24 -0800330}
331
332void
333AutoPrefixPropagator::afterRibErase(const ControlParameters& parameters,
334 const CommandOptions& options)
335{
336 auto entryIt = m_propagatedEntries.find(parameters.getName());
337 BOOST_ASSERT(entryIt != m_propagatedEntries.end());
338
339 bool hasPropagationSucceeded = entryIt->second.isPropagated();
340
341 // --> "RELEASED"
342 m_propagatedEntries.erase(entryIt);
343
344 if (!m_hasConnectedHub) {
345 NFD_LOG_INFO("no hub connected to revoke propagation of " << parameters.getName());
346 return;
347 }
348
349 if (!hasPropagationSucceeded) {
350 NFD_LOG_INFO("propagation has not succeeded: " << parameters.getName());
351 return;
352 }
353
Yanbiao Li5ad19fe2016-09-03 07:16:46 +0000354 withdraw(parameters, options, m_baseRetryWait);
Yanbiao Lid7c96362015-01-30 23:58:24 -0800355}
356
357void
358AutoPrefixPropagator::afterHubConnect()
359{
360 NFD_LOG_INFO("redo " << m_propagatedEntries.size()
361 << " propagations when new Hub connectivity is built.");
362
363 std::vector<PropagatedEntryIt> regEntryIterators;
364 for (auto it = m_propagatedEntries.begin() ; it != m_propagatedEntries.end() ; it ++) {
365 BOOST_ASSERT(it->second.isNew());
366 regEntryIterators.push_back(it);
367 }
368
369 for (auto&& it : regEntryIterators) {
370 auto parameters = m_controlParameters;
371 auto options = m_commandOptions;
372
373 redoPropagation(it,
374 parameters.setName(it->first),
375 options.setSigningInfo(signingByIdentity(it->second.getSigningIdentity())),
376 m_baseRetryWait);
377 }
378}
379
380void
381AutoPrefixPropagator::afterHubDisconnect()
382{
383 for (auto&& entry : m_propagatedEntries) {
384 // --> NEW
385 BOOST_ASSERT(!entry.second.isNew());
386 entry.second.initialize();
387 }
388}
389
390void
391AutoPrefixPropagator::afterPropagateSucceed(const ControlParameters& parameters,
392 const CommandOptions& options,
Davide Pesaventoe1bdc082018-10-11 21:20:23 -0400393 const EventCallback& refreshEvent)
Yanbiao Lid7c96362015-01-30 23:58:24 -0800394{
395 NFD_LOG_TRACE("success to propagate " << parameters.getName());
396
397 auto entryIt = m_propagatedEntries.find(parameters.getName());
398 if (entryIt == m_propagatedEntries.end()) {
399 // propagation should be revoked if this entry has been erased (i.e., be in RELEASED state)
400 NFD_LOG_DEBUG("Already erased!");
401 ControlParameters newParameters = parameters;
Yanbiao Li5ad19fe2016-09-03 07:16:46 +0000402 return withdraw(newParameters.unsetCost(), options, m_baseRetryWait);
Yanbiao Lid7c96362015-01-30 23:58:24 -0800403 }
404
405 // PROPAGATING --> PROPAGATED
406 BOOST_ASSERT(entryIt->second.isPropagating());
Davide Pesaventoe1bdc082018-10-11 21:20:23 -0400407 entryIt->second.succeed(m_scheduler, m_scheduler.scheduleEvent(m_refreshInterval, refreshEvent));
Yanbiao Lid7c96362015-01-30 23:58:24 -0800408}
409
410void
Junxiao Shi29b41282016-08-22 03:47:02 +0000411AutoPrefixPropagator::afterPropagateFail(const ndn::nfd::ControlResponse& response,
Yanbiao Lid7c96362015-01-30 23:58:24 -0800412 const ControlParameters& parameters,
413 const CommandOptions& options,
414 time::seconds retryWaitTime,
Davide Pesaventoe1bdc082018-10-11 21:20:23 -0400415 const EventCallback& retryEvent)
Yanbiao Lid7c96362015-01-30 23:58:24 -0800416{
417 NFD_LOG_TRACE("fail to propagate " << parameters.getName()
Junxiao Shi29b41282016-08-22 03:47:02 +0000418 << "\n\t reason:" << response.getText()
Yanbiao Lid7c96362015-01-30 23:58:24 -0800419 << "\n\t retry wait time: " << retryWaitTime);
420
421 auto entryIt = m_propagatedEntries.find(parameters.getName());
422 if (entryIt == m_propagatedEntries.end()) {
423 // current state is RELEASED
424 return;
425 }
426
427 // PROPAGATING --> PROPAGATE_FAIL
428 BOOST_ASSERT(entryIt->second.isPropagating());
Davide Pesaventoe1bdc082018-10-11 21:20:23 -0400429 entryIt->second.fail(m_scheduler, m_scheduler.scheduleEvent(retryWaitTime, retryEvent));
Yanbiao Lid7c96362015-01-30 23:58:24 -0800430}
431
432void
433AutoPrefixPropagator::afterRevokeSucceed(const ControlParameters& parameters,
434 const CommandOptions& options,
435 time::seconds retryWaitTime)
436{
437 NFD_LOG_TRACE("success to revoke propagation of " << parameters.getName());
438
439 auto entryIt = m_propagatedEntries.find(parameters.getName());
440 if (m_propagatedEntries.end() != entryIt && !entryIt->second.isPropagateFail()) {
441 // if is not RELEASED or PROPAGATE_FAIL
442 NFD_LOG_DEBUG("propagated entry still exists");
443
444 // PROPAGATING / PROPAGATED --> PROPAGATING
445 BOOST_ASSERT(!entryIt->second.isNew());
446 entryIt->second.startPropagation();
447
448 ControlParameters newParameters = parameters;
Yanbiao Li5ad19fe2016-09-03 07:16:46 +0000449 advertise(newParameters.setCost(m_controlParameters.getCost()), options, retryWaitTime);
Yanbiao Lid7c96362015-01-30 23:58:24 -0800450 }
451}
452
453void
Junxiao Shi29b41282016-08-22 03:47:02 +0000454AutoPrefixPropagator::afterRevokeFail(const ndn::nfd::ControlResponse& response,
455 const ControlParameters& parameters,
456 const CommandOptions& options)
Yanbiao Lid7c96362015-01-30 23:58:24 -0800457{
458 NFD_LOG_INFO("fail to revoke the propagation of " << parameters.getName()
Junxiao Shi29b41282016-08-22 03:47:02 +0000459 << "\n\t reason:" << response.getText());
Yanbiao Lid7c96362015-01-30 23:58:24 -0800460}
461
462void
463AutoPrefixPropagator::onRefreshTimer(const ControlParameters& parameters,
464 const CommandOptions& options)
465{
466 auto entryIt = m_propagatedEntries.find(parameters.getName());
467 BOOST_ASSERT(entryIt != m_propagatedEntries.end() && entryIt->second.isPropagated());
468 redoPropagation(entryIt, parameters, options, m_baseRetryWait);
469}
470
471void
472AutoPrefixPropagator::onRetryTimer(const ControlParameters& parameters,
473 const CommandOptions& options,
474 time::seconds retryWaitTime)
475{
476 auto entryIt = m_propagatedEntries.find(parameters.getName());
477 BOOST_ASSERT(entryIt != m_propagatedEntries.end() && entryIt->second.isPropagateFail());
478 redoPropagation(entryIt, parameters, options, retryWaitTime);
479}
480
481} // namespace rib
482} // namespace nfd