blob: d3e9e8642aeffdc42dc590c80156948ed4266970 [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,
Yanbiao Lif32ca892017-05-31 10:08:07 +0800181 // if there is no hub connected to propagate this prefix.
182 if (entryIt->second.isNew()) {
183 NFD_LOG_INFO("no hub connected to propagate "
184 << propagateParameters.parameters.getName());
185 }
186 else {
187 NFD_LOG_INFO("prefix has already been propagated: "
188 << propagateParameters.parameters.getName());
189 }
Yanbiao Lid7c96362015-01-30 23:58:24 -0800190 return;
191 }
192
193 afterRibInsert(propagateParameters.parameters, propagateParameters.options);
194}
195
196void
197AutoPrefixPropagator::afterEraseRibEntry(const Name& prefix)
198{
199 if (LOCAL_REGISTRATION_PREFIX.isPrefixOf(prefix)) {
200 NFD_LOG_INFO("local unregistration only for " << prefix);
201 return;
202 }
203
204 if (prefix == LINK_LOCAL_NFD_PREFIX) {
205 NFD_LOG_INFO("disconnected to hub with prefix: " << prefix);
206
207 m_hasConnectedHub = false;
208 return afterHubDisconnect();
209 }
210
211 auto propagateParameters = getPrefixPropagationParameters(prefix);
212 if (!propagateParameters.isValid) {
213 NFD_LOG_INFO("no signing identity available for: " << prefix);
214 return;
215 }
216
217 auto entryIt = m_propagatedEntries.find(propagateParameters.parameters.getName());
218 if (entryIt == m_propagatedEntries.end()) {
219 NFD_LOG_INFO("prefix has not been propagated yet: "
220 << propagateParameters.parameters.getName());
221 return;
222 }
223
224 for (auto&& ribTableEntry : m_rib) {
225 if (propagateParameters.parameters.getName().isPrefixOf(ribTableEntry.first) &&
226 propagateParameters.options.getSigningInfo().getSignerName() ==
227 getPrefixPropagationParameters(ribTableEntry.first)
228 .options.getSigningInfo().getSignerName()) {
229 NFD_LOG_INFO("should be kept for another RIB entry: " << ribTableEntry.first);
230 return;
231 }
232 }
233
234 afterRibErase(propagateParameters.parameters.unsetCost(), propagateParameters.options);
235}
236
237bool
238AutoPrefixPropagator::doesCurrentPropagatedPrefixWork(const Name& prefix)
239{
240 auto propagateParameters = getPrefixPropagationParameters(prefix);
241 if (!propagateParameters.isValid) {
242 // no identity can sign the input prefix
243 return false;
244 }
245
246 // there is at least one identity can sign the input prefix, so the prefix selected for
247 // propagation (i.e., propagateParameters.parameters.getName()) must be a prefix of the input
248 // prefix. Namely it's either equal to the input prefix or a better choice.
249 return propagateParameters.parameters.getName().size() == prefix.size();
250}
251
252void
253AutoPrefixPropagator::redoPropagation(PropagatedEntryIt entryIt,
254 const ControlParameters& parameters,
255 const CommandOptions& options,
256 time::seconds retryWaitTime)
257{
258 if (doesCurrentPropagatedPrefixWork(parameters.getName())) {
259 // PROPAGATED / PROPAGATE_FAIL --> PROPAGATING
260 entryIt->second.startPropagation();
Yanbiao Li5ad19fe2016-09-03 07:16:46 +0000261 return advertise(parameters, options, retryWaitTime);
Yanbiao Lid7c96362015-01-30 23:58:24 -0800262 }
263
264 NFD_LOG_INFO("current propagated prefix does not work any more");
265 m_propagatedEntries.erase(entryIt);
266
267 // re-handle all locally RIB entries that can be covered by this propagated prefix
268 for (auto&& ribTableEntry : m_rib) {
269 if (parameters.getName().isPrefixOf(ribTableEntry.first)) {
270 afterInsertRibEntry(ribTableEntry.first);
271 }
272 }
273}
274
275void
Yanbiao Li5ad19fe2016-09-03 07:16:46 +0000276AutoPrefixPropagator::advertise(const ControlParameters& parameters,
277 const CommandOptions& options,
278 time::seconds retryWaitTime)
Yanbiao Lid7c96362015-01-30 23:58:24 -0800279{
Yanbiao Li5ad19fe2016-09-03 07:16:46 +0000280 NFD_LOG_INFO("advertise " << parameters.getName());
Yanbiao Lid7c96362015-01-30 23:58:24 -0800281
Alexander Afanasyev635bf202017-03-09 21:57:34 +0000282 scheduler::EventCallback refreshEvent =
Yanbiao Lid7c96362015-01-30 23:58:24 -0800283 bind(&AutoPrefixPropagator::onRefreshTimer, this, parameters, options);
Alexander Afanasyev635bf202017-03-09 21:57:34 +0000284 scheduler::EventCallback retryEvent =
Yanbiao Lid7c96362015-01-30 23:58:24 -0800285 bind(&AutoPrefixPropagator::onRetryTimer, this, parameters, options,
286 std::min(m_maxRetryWait, retryWaitTime * 2));
287
288 m_nfdController.start<ndn::nfd::RibRegisterCommand>(
289 parameters,
290 bind(&AutoPrefixPropagator::afterPropagateSucceed, this, parameters, options, refreshEvent),
291 bind(&AutoPrefixPropagator::afterPropagateFail,
Junxiao Shi29b41282016-08-22 03:47:02 +0000292 this, _1, parameters, options, retryWaitTime, retryEvent),
Yanbiao Lid7c96362015-01-30 23:58:24 -0800293 options);
294}
295
296void
Yanbiao Li5ad19fe2016-09-03 07:16:46 +0000297AutoPrefixPropagator::withdraw(const ControlParameters& parameters,
298 const CommandOptions& options,
299 time::seconds retryWaitTime)
Yanbiao Lid7c96362015-01-30 23:58:24 -0800300{
Yanbiao Li5ad19fe2016-09-03 07:16:46 +0000301 NFD_LOG_INFO("withdraw " << parameters.getName());
Yanbiao Lid7c96362015-01-30 23:58:24 -0800302
303 m_nfdController.start<ndn::nfd::RibUnregisterCommand>(
304 parameters,
305 bind(&AutoPrefixPropagator::afterRevokeSucceed, this, parameters, options, retryWaitTime),
Junxiao Shi29b41282016-08-22 03:47:02 +0000306 bind(&AutoPrefixPropagator::afterRevokeFail, this, _1, parameters, options),
Yanbiao Lid7c96362015-01-30 23:58:24 -0800307 options);
308}
309
310void
311AutoPrefixPropagator::afterRibInsert(const ControlParameters& parameters,
312 const CommandOptions& options)
313{
314 BOOST_ASSERT(m_propagatedEntries.find(parameters.getName()) == m_propagatedEntries.end());
315
316 // keep valid entries although there is no connectivity to hub
317 auto& entry = m_propagatedEntries[parameters.getName()]
318 .setSigningIdentity(options.getSigningInfo().getSignerName());
319
320 if (!m_hasConnectedHub) {
321 NFD_LOG_INFO("no hub connected to propagate " << parameters.getName());
322 return;
323 }
324
325 // NEW --> PROPAGATING
326 entry.startPropagation();
Yanbiao Li5ad19fe2016-09-03 07:16:46 +0000327 advertise(parameters, options, m_baseRetryWait);
Yanbiao Lid7c96362015-01-30 23:58:24 -0800328}
329
330void
331AutoPrefixPropagator::afterRibErase(const ControlParameters& parameters,
332 const CommandOptions& options)
333{
334 auto entryIt = m_propagatedEntries.find(parameters.getName());
335 BOOST_ASSERT(entryIt != m_propagatedEntries.end());
336
337 bool hasPropagationSucceeded = entryIt->second.isPropagated();
338
339 // --> "RELEASED"
340 m_propagatedEntries.erase(entryIt);
341
342 if (!m_hasConnectedHub) {
343 NFD_LOG_INFO("no hub connected to revoke propagation of " << parameters.getName());
344 return;
345 }
346
347 if (!hasPropagationSucceeded) {
348 NFD_LOG_INFO("propagation has not succeeded: " << parameters.getName());
349 return;
350 }
351
Yanbiao Li5ad19fe2016-09-03 07:16:46 +0000352 withdraw(parameters, options, m_baseRetryWait);
Yanbiao Lid7c96362015-01-30 23:58:24 -0800353}
354
355void
356AutoPrefixPropagator::afterHubConnect()
357{
358 NFD_LOG_INFO("redo " << m_propagatedEntries.size()
359 << " propagations when new Hub connectivity is built.");
360
361 std::vector<PropagatedEntryIt> regEntryIterators;
362 for (auto it = m_propagatedEntries.begin() ; it != m_propagatedEntries.end() ; it ++) {
363 BOOST_ASSERT(it->second.isNew());
364 regEntryIterators.push_back(it);
365 }
366
367 for (auto&& it : regEntryIterators) {
368 auto parameters = m_controlParameters;
369 auto options = m_commandOptions;
370
371 redoPropagation(it,
372 parameters.setName(it->first),
373 options.setSigningInfo(signingByIdentity(it->second.getSigningIdentity())),
374 m_baseRetryWait);
375 }
376}
377
378void
379AutoPrefixPropagator::afterHubDisconnect()
380{
381 for (auto&& entry : m_propagatedEntries) {
382 // --> NEW
383 BOOST_ASSERT(!entry.second.isNew());
384 entry.second.initialize();
385 }
386}
387
388void
389AutoPrefixPropagator::afterPropagateSucceed(const ControlParameters& parameters,
390 const CommandOptions& options,
Alexander Afanasyev635bf202017-03-09 21:57:34 +0000391 const scheduler::EventCallback& refreshEvent)
Yanbiao Lid7c96362015-01-30 23:58:24 -0800392{
393 NFD_LOG_TRACE("success to propagate " << parameters.getName());
394
395 auto entryIt = m_propagatedEntries.find(parameters.getName());
396 if (entryIt == m_propagatedEntries.end()) {
397 // propagation should be revoked if this entry has been erased (i.e., be in RELEASED state)
398 NFD_LOG_DEBUG("Already erased!");
399 ControlParameters newParameters = parameters;
Yanbiao Li5ad19fe2016-09-03 07:16:46 +0000400 return withdraw(newParameters.unsetCost(), options, m_baseRetryWait);
Yanbiao Lid7c96362015-01-30 23:58:24 -0800401 }
402
403 // PROPAGATING --> PROPAGATED
404 BOOST_ASSERT(entryIt->second.isPropagating());
405 entryIt->second.succeed(scheduler::schedule(m_refreshInterval, refreshEvent));
406}
407
408void
Junxiao Shi29b41282016-08-22 03:47:02 +0000409AutoPrefixPropagator::afterPropagateFail(const ndn::nfd::ControlResponse& response,
Yanbiao Lid7c96362015-01-30 23:58:24 -0800410 const ControlParameters& parameters,
411 const CommandOptions& options,
412 time::seconds retryWaitTime,
Alexander Afanasyev635bf202017-03-09 21:57:34 +0000413 const scheduler::EventCallback& retryEvent)
Yanbiao Lid7c96362015-01-30 23:58:24 -0800414{
415 NFD_LOG_TRACE("fail to propagate " << parameters.getName()
Junxiao Shi29b41282016-08-22 03:47:02 +0000416 << "\n\t reason:" << response.getText()
Yanbiao Lid7c96362015-01-30 23:58:24 -0800417 << "\n\t retry wait time: " << retryWaitTime);
418
419 auto entryIt = m_propagatedEntries.find(parameters.getName());
420 if (entryIt == m_propagatedEntries.end()) {
421 // current state is RELEASED
422 return;
423 }
424
425 // PROPAGATING --> PROPAGATE_FAIL
426 BOOST_ASSERT(entryIt->second.isPropagating());
427 entryIt->second.fail(scheduler::schedule(retryWaitTime, retryEvent));
428}
429
430void
431AutoPrefixPropagator::afterRevokeSucceed(const ControlParameters& parameters,
432 const CommandOptions& options,
433 time::seconds retryWaitTime)
434{
435 NFD_LOG_TRACE("success to revoke propagation of " << parameters.getName());
436
437 auto entryIt = m_propagatedEntries.find(parameters.getName());
438 if (m_propagatedEntries.end() != entryIt && !entryIt->second.isPropagateFail()) {
439 // if is not RELEASED or PROPAGATE_FAIL
440 NFD_LOG_DEBUG("propagated entry still exists");
441
442 // PROPAGATING / PROPAGATED --> PROPAGATING
443 BOOST_ASSERT(!entryIt->second.isNew());
444 entryIt->second.startPropagation();
445
446 ControlParameters newParameters = parameters;
Yanbiao Li5ad19fe2016-09-03 07:16:46 +0000447 advertise(newParameters.setCost(m_controlParameters.getCost()), options, retryWaitTime);
Yanbiao Lid7c96362015-01-30 23:58:24 -0800448 }
449}
450
451void
Junxiao Shi29b41282016-08-22 03:47:02 +0000452AutoPrefixPropagator::afterRevokeFail(const ndn::nfd::ControlResponse& response,
453 const ControlParameters& parameters,
454 const CommandOptions& options)
Yanbiao Lid7c96362015-01-30 23:58:24 -0800455{
456 NFD_LOG_INFO("fail to revoke the propagation of " << parameters.getName()
Junxiao Shi29b41282016-08-22 03:47:02 +0000457 << "\n\t reason:" << response.getText());
Yanbiao Lid7c96362015-01-30 23:58:24 -0800458}
459
460void
461AutoPrefixPropagator::onRefreshTimer(const ControlParameters& parameters,
462 const CommandOptions& options)
463{
464 auto entryIt = m_propagatedEntries.find(parameters.getName());
465 BOOST_ASSERT(entryIt != m_propagatedEntries.end() && entryIt->second.isPropagated());
466 redoPropagation(entryIt, parameters, options, m_baseRetryWait);
467}
468
469void
470AutoPrefixPropagator::onRetryTimer(const ControlParameters& parameters,
471 const CommandOptions& options,
472 time::seconds retryWaitTime)
473{
474 auto entryIt = m_propagatedEntries.find(parameters.getName());
475 BOOST_ASSERT(entryIt != m_propagatedEntries.end() && entryIt->second.isPropagateFail());
476 redoPropagation(entryIt, parameters, options, retryWaitTime);
477}
478
479} // namespace rib
480} // namespace nfd