blob: 802a10550d0c08374f21d037936a8ce74592c3d9 [file] [log] [blame]
Yanbiao Lid7c96362015-01-30 23:58:24 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesaventoe1bdc082018-10-11 21:20:23 -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#ifndef NFD_RIB_AUTO_PREFIX_PROPAGATOR_HPP
27#define NFD_RIB_AUTO_PREFIX_PROPAGATOR_HPP
28
Davide Pesaventoe1bdc082018-10-11 21:20:23 -040029#include "propagated-entry.hpp"
Yanbiao Lid7c96362015-01-30 23:58:24 -080030#include "rib.hpp"
31#include "core/config-file.hpp"
Yanbiao Lid7c96362015-01-30 23:58:24 -080032
33#include <ndn-cxx/security/key-chain.hpp>
Junxiao Shi25c6ce42016-09-09 13:49:59 +000034#include <ndn-cxx/mgmt/nfd/controller.hpp>
35#include <ndn-cxx/mgmt/nfd/control-command.hpp>
36#include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
37#include <ndn-cxx/mgmt/nfd/command-options.hpp>
Davide Pesaventoe1bdc082018-10-11 21:20:23 -040038#include <ndn-cxx/util/scheduler.hpp>
Yanbiao Lid7c96362015-01-30 23:58:24 -080039#include <ndn-cxx/util/signal.hpp>
40
41namespace nfd {
42namespace rib {
43
44/** @brief provides automatic prefix propagation feature
45 *
46 * The AutoPrefixPropagator monitors changes to local RIB, and registers prefixes onto a
47 * connected gateway router (HUB), so that Interests under propagated prefixes will be forwarded
48 * toward the local host by the HUB.
49 *
50 * The route origin of propagated prefix is CLIENT, as shown on the HUB.
51 *
52 * Connectivity to a HUB is indicated with a special RIB entry "ndn:/localhop/nfd".
53 * Currently, the AutoPrefixPropagator can process the connection to at most one HUB.
54 *
55 * For every RIB entry except "ndn:/localhop/nfd" and those starting with "ndn:/localhost", the
56 * AutoPrefixPropagator queries the local KeyChain for signing identities that is authorized
57 * to sign a prefix registration command of a prefix of the RIB prefix.
58 *
59 * If one or more signing identities are found, the identity that can sign a prefix registration
60 * command of the shortest prefix is chosen, and the AutoPrefixPropagator will attempt to
61 * propagte a prefix to the HUB using the shortest prefix. It's noteworthy that no route flags will
62 * be inherited from the local registration.
63 * If no signing identity is available, no prefix of the RIB entry is propagated to the HUB.
64 *
65 * When a RIB entry is erased, the corresponding propagated entry would be revoked,
66 * unless another local RIB entry is causing the propagation of that prefix.
67 *
68 * After a successful propagation, the AutoPrefixPropagator will refresh the propagation
69 * periodically by resending the registration command.
70 *
71 * In case of a failure or timeout in a registration command, the command will be retried with an
72 * exponential back-off strategy.
73 *
74 * The AutoPrefixPropagator can be configured in NFD configuration file, at the
75 * rib.auto_prefix_propagate section.
76 */
77class AutoPrefixPropagator : noncopyable
78{
79public:
80 class Error : public std::runtime_error
81 {
82 public:
83 explicit
84 Error(const std::string& what)
85 : std::runtime_error(what)
86 {
87 }
88 };
89
90 AutoPrefixPropagator(ndn::nfd::Controller& controller,
91 ndn::KeyChain& keyChain,
Davide Pesaventoe1bdc082018-10-11 21:20:23 -040092 ndn::util::Scheduler& scheduler,
Yanbiao Lid7c96362015-01-30 23:58:24 -080093 Rib& rib);
94 /**
95 * @brief load the "auto_prefix_propagate" section from config file
96 *
97 * @param configSection the sub section in "rib" section.
98 */
99 void
100 loadConfig(const ConfigSection& configSection);
101
102 /**
103 * @brief enable automatic prefix propagation
104 */
105 void
106 enable();
107
108 /**
109 * @brief disable automatic prefix propagation
110 */
111 void
112 disable();
113
114PUBLIC_WITH_TESTS_ELSE_PRIVATE: // helpers
115 /**
116 * When a local RIB prefix triggers prefix propagation, we propagate the shortest identity that
117 * can sign this prefix to the HUB.
118 *
119 * Thus, the propagated prefix does not equal to local RIB prefix.
120 * So it needs separate storage instead of storing within the RIB.
121 *
122 * the propagated prefix is used as the key to retrive the corresponding entry.
123 */
124 typedef std::unordered_map<Name, PropagatedEntry> PropagatedEntryList;
125 typedef PropagatedEntryList::iterator PropagatedEntryIt;
126
127 /**
128 * @brief parameters used by the registration commands for prefix propagation
129 *
130 * consists of a ControlParameters and a CommandOptions, as well as a bool variable indicates
131 * whether this set of parameters is valid (i.e., the signing identity exists)
132 */
133 struct PrefixPropagationParameters
134 {
135 bool isValid;
136 ndn::nfd::ControlParameters parameters;
137 ndn::nfd::CommandOptions options;
138 };
139
140 /**
141 * @brief get the required parameters for prefix propagation.
142 *
143 * given a local RIB prefix @p localRibPrefix, find out, in local KeyChain, a proper identity
144 * whose namespace covers the input prefix. If there is no desired identity, return a invalid
145 * PrefixPropagationParameters.
146 *
147 * Otherwise, set the selected identity as the signing identity in CommandOptions. Meanwhile,
148 * set this identity (or its prefix with the last component eliminated if it ends with "nrd")
149 * as the name of ControlParameters.
150 *
151 * @return the PrefixPropagationParameters.
152 */
153 PrefixPropagationParameters
154 getPrefixPropagationParameters(const Name& localRibPrefix);
155
156 /**
157 * @brief check whether current propagated prefix still works
158 *
159 * the current propagated prefix @p prefix will still work if and only if its corresponding
160 * signing identity still exists and there is no better signing identity covering it.
161 *
162 * @return true if current propagated prefix still works, otherwise false
163 */
164 bool
165 doesCurrentPropagatedPrefixWork(const Name& prefix);
166
167 /**
168 * @brief process re-propagation for the given propagated entry
169 *
170 * This function may be invoked in 3 cases:
171 * 1. After the hub is connected to redo some propagations.
172 * 2. On refresh timer to handle refresh requests.
173 * 3. On retry timer to handle retry requests.
174 *
175 * @param entryIt the propagated entry need to do re-propagation
176 * @param parameters the ControlParameters used by registration commands for propagation
177 * @param options the CommandOptions used for registration commands for propagation
178 * @param retryWaitTime the current wait time before retrying propagation
179 */
180 void
181 redoPropagation(PropagatedEntryIt entryIt,
182 const ndn::nfd::ControlParameters& parameters,
183 const ndn::nfd::CommandOptions& options,
184 time::seconds retryWaitTime);
185
186private:
187 /**
188 * @brief send out the registration command for propagation
189 *
190 * Before sending out the command, two events, for refresh and retry respectively, are
191 * established (but not scheduled) and assigned to two callbacks, afterPropagateSucceed and
192 * afterPropagateFail respectively.
193 *
194 * The retry event requires an argument to define the retry wait time, which is calculated
195 * according to the back-off policy based on current retry wait time @p retryWaitTime and the
196 * maxRetryWait.
197 *
198 * The baseRetryWait and maxRetryWait used in back-off strategy are all configured at
199 * rib.auto_prefix_propagate.base_retry_wait and
200 * rib.auto_prefix_propagate.max_retry_wait respectively
201
202 * @param parameters the ControlParameters used by the registration command for propagation
203 * @param options the CommandOptions used by the registration command for propagation
204 * @param retryWaitTime the current wait time before retrying propagation
205 */
206 void
Yanbiao Li5ad19fe2016-09-03 07:16:46 +0000207 advertise(const ndn::nfd::ControlParameters& parameters,
208 const ndn::nfd::CommandOptions& options,
209 time::seconds retryWaitTime);
Yanbiao Lid7c96362015-01-30 23:58:24 -0800210
211 /**
212 * @brief send out the unregistration command to revoke the corresponding propagation.
213 *
214 * @param parameters the ControlParameters used by the unregistration command for revocation
215 * @param options the CommandOptions used by the unregistration command for revocation
216 * @param retryWaitTime the current wait time before retrying propagation
217 */
218 void
Yanbiao Li5ad19fe2016-09-03 07:16:46 +0000219 withdraw(const ndn::nfd::ControlParameters& parameters,
220 const ndn::nfd::CommandOptions& options,
221 time::seconds retryWaitTime);
Yanbiao Lid7c96362015-01-30 23:58:24 -0800222
223 /**
224 * @brief invoked when Rib::afterInsertEntry signal is emitted
225 *
226 * step1: if the local RIB prefix @param prefix is for local use only, return
227 * step2: if the local RIB prefix @param prefix is a hub prefix, invoke afterHubConnect
228 * step3: if no valid PrefixPropagationParameters can be found for the local RIB prefix
229 * @param prefix, or the propagated prefix has already been processed, return
230 * step4: invoke afterRibInsert
231 */
232 void
233 afterInsertRibEntry(const Name& prefix);
234
235 /**
236 * @brief invoked when Rib::afterEraseEntry signal is emitted
237 *
238 * step1: if local RIB prefix @param prefix is for local use only, return
239 * step2: if local RIB prefix @param prefix is a hub prefix, invoke afterHubDisconnect
240 * step3: if no valid PrefixPropagationParameters can be found for local RIB prefix
241 * @param prefix, or there are other local RIB prefixes can be covered by the propagated
242 * prefix, return
243 * step4: invoke afterRibErase
244 */
245 void
246 afterEraseRibEntry(const Name& prefix);
247
248PUBLIC_WITH_TESTS_ELSE_PRIVATE: // PropagatedEntry state changes
249 /**
250 * @brief invoked after rib insertion for non-hub prefixes
251 * @pre the PropagatedEntry is in RELEASED state
252 * @post the PropagatedEntry will be in NEW state
253 *
254 * @param parameters the ControlParameters used by registration commands for propagation
255 * @param options the CommandOptions used by registration commands for propagation
256 */
257 void
258 afterRibInsert(const ndn::nfd::ControlParameters& parameters,
259 const ndn::nfd::CommandOptions& options);
260
261 /**
262 * @brief invoked after rib deletion for non-hub prefixes
263 * @pre the PropagatedEntry is not in RELEASED state
264 * @post the PropagatedEntry will be in RELEASED state
265 *
266 * @param parameters the ControlParameters used by registration commands for propagation
267 * @param options the CommandOptions used by registration commands for propagation
268 */
269 void
270 afterRibErase(const ndn::nfd::ControlParameters& parameters,
271 const ndn::nfd::CommandOptions& options);
272
273 /**
274 * @brief invoked after the hub is connected
275 * @pre the PropagatedEntry is in NEW state or RELEASED state
276 * @post the PropagatedEntry will be in PROPAGATING state or keep in RELEASED state
277 *
278 * call redoPropagation for each propagated entry.
279 */
280 void
281 afterHubConnect();
282
283 /**
284 * @brief invoked after the hub is disconnected
285 * @pre the PropagatedEntry is not in NEW state
286 * @post the PropagatedEntry will be in NEW state or keep in RELEASED state
287 *
288 * for each propagated entry, switch its state to NEW and cancel its event.
289 */
290 void
291 afterHubDisconnect();
292
293 /**
294 * @brief invoked after propagation succeeds
295 * @pre the PropagatedEntry is in PROPAGATING state or RELEASED state
296 * @post the PropagatedEntry will be in PROPAGATED state or keep in RELEASED state
297 *
298 * If the PropagatedEntry does not exist (in RELEASED state), an unregistration command is
299 * sent immediately for revocation.
300 *
301 * If the PropagatedEntry is in PROPAGATING state, switch it to PROPAGATED, and schedule a
302 * refresh timer to redo propagation after a duration, which is configured at
303 * rib.auto_prefix_propagate.refresh_interval.
304 *
305 * Otherwise, make a copy of the ControlParameters @p parameters, unset its Cost field, and then
Yanbiao Li5ad19fe2016-09-03 07:16:46 +0000306 * invoke withdraw with this new ControlParameters.
Yanbiao Lid7c96362015-01-30 23:58:24 -0800307 *
308 * @param parameters the ControlParameters used by the registration command for propagation
309 * @param options the CommandOptions used by the registration command for propagation
310 * @param refreshEvent the event of refreshing propagation
311 */
312 void
313 afterPropagateSucceed(const ndn::nfd::ControlParameters& parameters,
314 const ndn::nfd::CommandOptions& options,
Davide Pesaventoe1bdc082018-10-11 21:20:23 -0400315 const ndn::util::scheduler::EventCallback& refreshEvent);
Yanbiao Lid7c96362015-01-30 23:58:24 -0800316
317 /**
318 * @brief invoked after propagation fails.
319 * @pre the PropagatedEntry is in PROPAGATING state or RELEASED state
320 * @post the PropagatedEntry will be in PROPAGATE_FAIL state or keep in RELEASED state
321 *
322 * If the PropagatedEntry still exists, schedule a retry timer to redo propagation
323 * after a duration defined by current retry time @p retryWaitTime
324 *
Junxiao Shi29b41282016-08-22 03:47:02 +0000325 * @param response ControlResponse from remote NFD-RIB
Yanbiao Lid7c96362015-01-30 23:58:24 -0800326 * @param parameters the ControlParameters used by the registration command for propagation
327 * @param options the CommandOptions used by registration command for propagation
328 * @param retryWaitTime the current wait time before retrying propagation
329 * @param retryEvent the event of retrying propagation
330 */
331 void
Junxiao Shi29b41282016-08-22 03:47:02 +0000332 afterPropagateFail(const ndn::nfd::ControlResponse& response,
Yanbiao Lid7c96362015-01-30 23:58:24 -0800333 const ndn::nfd::ControlParameters& parameters,
334 const ndn::nfd::CommandOptions& options,
335 time::seconds retryWaitTime,
Davide Pesaventoe1bdc082018-10-11 21:20:23 -0400336 const ndn::util::scheduler::EventCallback& retryEvent);
Yanbiao Lid7c96362015-01-30 23:58:24 -0800337
338 /**
339 * @brief invoked after revocation succeeds
340 * @pre the PropagatedEntry is not in NEW state
341 * @post the PropagatedEntry will be in PROPAGATING state, or keep in PROPAGATE_FAIL state,
342 * or keep in RELEASED state
343 *
344 * If the PropagatedEntry still exists and is not in PROPAGATE_FAIL state, switch it to
345 * PROPAGATING. Then make a copy of the ControlParameters @p parameters, reset its Cost, and
Yanbiao Li5ad19fe2016-09-03 07:16:46 +0000346 * invoke advertise with this new ControlParameters.
Yanbiao Lid7c96362015-01-30 23:58:24 -0800347 *
348 * @param parameters the ControlParameters used by the unregistration command for revocation
349 * @param options the CommandOptions used by the unregistration command for revocation
350 * @param retryWaitTime the current wait time before retrying propagation
351 */
352 void
353 afterRevokeSucceed(const ndn::nfd::ControlParameters& parameters,
354 const ndn::nfd::CommandOptions& options,
355 time::seconds retryWaitTime);
356
357 /**
358 * @brief invoked after revocation fails.
359 *
Junxiao Shi29b41282016-08-22 03:47:02 +0000360 * @param response ControlResponse from remote NFD-RIB
Yanbiao Lid7c96362015-01-30 23:58:24 -0800361 * @param parameters the ControlParameters used by the unregistration command for revocation
362 * @param options the CommandOptions used by the unregistration command for revocation
363 */
364 void
Junxiao Shi29b41282016-08-22 03:47:02 +0000365 afterRevokeFail(const ndn::nfd::ControlResponse& response,
Yanbiao Lid7c96362015-01-30 23:58:24 -0800366 const ndn::nfd::ControlParameters& parameters,
367 const ndn::nfd::CommandOptions& options);
368
369 /**
370 * @brief invoked when the refresh timer is triggered.
371 * @pre the PropagatedEntry is in PROPAGATED state
372 * @post the PropagatedEntry will be in PROPAGATING state
373 *
374 * call redoPropagation to handle this refresh request
375 *
376 * @param parameters the ControlParameters used by registration commands for propagation
377 * @param options the CommandOptions used by registration commands for propagation
378 */
379 void
380 onRefreshTimer(const ndn::nfd::ControlParameters& parameters,
381 const ndn::nfd::CommandOptions& options);
382
383 /**
384 * @brief invoked when the retry timer is triggered.
385 * @pre the PropagatedEntry is in PROPAGATE_FAIL state
386 * @post the PropagatedEntry will be in PROPAGATING state
387 *
388 * call redoPropagation to handle this retry request
389 *
390 * @param parameters the ControlParameters used by registration commands for propagation
391 * @param options the CommandOptions used by registration commands for propagation
392 * @param retryWaitTime the current wait time before retrying propagation
393 */
394 void
395 onRetryTimer(const ndn::nfd::ControlParameters& parameters,
396 const ndn::nfd::CommandOptions& options,
397 time::seconds retryWaitTime);
398
399PUBLIC_WITH_TESTS_ELSE_PRIVATE:
400 ndn::nfd::Controller& m_nfdController;
401 ndn::KeyChain& m_keyChain;
Davide Pesaventoe1bdc082018-10-11 21:20:23 -0400402 ndn::util::Scheduler& m_scheduler;
Yanbiao Lid7c96362015-01-30 23:58:24 -0800403 Rib& m_rib;
404 ndn::util::signal::ScopedConnection m_afterInsertConnection;
405 ndn::util::signal::ScopedConnection m_afterEraseConnection;
406 ndn::nfd::ControlParameters m_controlParameters;
407 ndn::nfd::CommandOptions m_commandOptions;
408 time::seconds m_refreshInterval;
409 time::seconds m_baseRetryWait;
410 time::seconds m_maxRetryWait;
411 bool m_hasConnectedHub;
412 PropagatedEntryList m_propagatedEntries;
413};
414
415} // namespace rib
416} // namespace nfd
417
418#endif // NFD_RIB_AUTO_PREFIX_PROPAGATOR_HPP