blob: 11ad67f4fe5f6e04c9f9b8186792121c577266b3 [file] [log] [blame]
Yanbiao Lid7c96362015-01-30 23:58:24 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014-2015, Regents of the University of California,
4 * 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
29#include "rib.hpp"
30#include "core/config-file.hpp"
31#include "rib-status-publisher.hpp"
32#include "propagated-entry.hpp"
33
34#include <ndn-cxx/security/key-chain.hpp>
35#include <ndn-cxx/management/nfd-controller.hpp>
36#include <ndn-cxx/management/nfd-control-command.hpp>
37#include <ndn-cxx/management/nfd-control-parameters.hpp>
38#include <ndn-cxx/management/nfd-command-options.hpp>
39#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,
92 Rib& rib);
93 /**
94 * @brief load the "auto_prefix_propagate" section from config file
95 *
96 * @param configSection the sub section in "rib" section.
97 */
98 void
99 loadConfig(const ConfigSection& configSection);
100
101 /**
102 * @brief enable automatic prefix propagation
103 */
104 void
105 enable();
106
107 /**
108 * @brief disable automatic prefix propagation
109 */
110 void
111 disable();
112
113PUBLIC_WITH_TESTS_ELSE_PRIVATE: // helpers
114 /**
115 * When a local RIB prefix triggers prefix propagation, we propagate the shortest identity that
116 * can sign this prefix to the HUB.
117 *
118 * Thus, the propagated prefix does not equal to local RIB prefix.
119 * So it needs separate storage instead of storing within the RIB.
120 *
121 * the propagated prefix is used as the key to retrive the corresponding entry.
122 */
123 typedef std::unordered_map<Name, PropagatedEntry> PropagatedEntryList;
124 typedef PropagatedEntryList::iterator PropagatedEntryIt;
125
126 /**
127 * @brief parameters used by the registration commands for prefix propagation
128 *
129 * consists of a ControlParameters and a CommandOptions, as well as a bool variable indicates
130 * whether this set of parameters is valid (i.e., the signing identity exists)
131 */
132 struct PrefixPropagationParameters
133 {
134 bool isValid;
135 ndn::nfd::ControlParameters parameters;
136 ndn::nfd::CommandOptions options;
137 };
138
139 /**
140 * @brief get the required parameters for prefix propagation.
141 *
142 * given a local RIB prefix @p localRibPrefix, find out, in local KeyChain, a proper identity
143 * whose namespace covers the input prefix. If there is no desired identity, return a invalid
144 * PrefixPropagationParameters.
145 *
146 * Otherwise, set the selected identity as the signing identity in CommandOptions. Meanwhile,
147 * set this identity (or its prefix with the last component eliminated if it ends with "nrd")
148 * as the name of ControlParameters.
149 *
150 * @return the PrefixPropagationParameters.
151 */
152 PrefixPropagationParameters
153 getPrefixPropagationParameters(const Name& localRibPrefix);
154
155 /**
156 * @brief check whether current propagated prefix still works
157 *
158 * the current propagated prefix @p prefix will still work if and only if its corresponding
159 * signing identity still exists and there is no better signing identity covering it.
160 *
161 * @return true if current propagated prefix still works, otherwise false
162 */
163 bool
164 doesCurrentPropagatedPrefixWork(const Name& prefix);
165
166 /**
167 * @brief process re-propagation for the given propagated entry
168 *
169 * This function may be invoked in 3 cases:
170 * 1. After the hub is connected to redo some propagations.
171 * 2. On refresh timer to handle refresh requests.
172 * 3. On retry timer to handle retry requests.
173 *
174 * @param entryIt the propagated entry need to do re-propagation
175 * @param parameters the ControlParameters used by registration commands for propagation
176 * @param options the CommandOptions used for registration commands for propagation
177 * @param retryWaitTime the current wait time before retrying propagation
178 */
179 void
180 redoPropagation(PropagatedEntryIt entryIt,
181 const ndn::nfd::ControlParameters& parameters,
182 const ndn::nfd::CommandOptions& options,
183 time::seconds retryWaitTime);
184
185private:
186 /**
187 * @brief send out the registration command for propagation
188 *
189 * Before sending out the command, two events, for refresh and retry respectively, are
190 * established (but not scheduled) and assigned to two callbacks, afterPropagateSucceed and
191 * afterPropagateFail respectively.
192 *
193 * The retry event requires an argument to define the retry wait time, which is calculated
194 * according to the back-off policy based on current retry wait time @p retryWaitTime and the
195 * maxRetryWait.
196 *
197 * The baseRetryWait and maxRetryWait used in back-off strategy are all configured at
198 * rib.auto_prefix_propagate.base_retry_wait and
199 * rib.auto_prefix_propagate.max_retry_wait respectively
200
201 * @param parameters the ControlParameters used by the registration command for propagation
202 * @param options the CommandOptions used by the registration command for propagation
203 * @param retryWaitTime the current wait time before retrying propagation
204 */
205 void
206 startPropagation(const ndn::nfd::ControlParameters& parameters,
207 const ndn::nfd::CommandOptions& options,
208 time::seconds retryWaitTime);
209
210 /**
211 * @brief send out the unregistration command to revoke the corresponding propagation.
212 *
213 * @param parameters the ControlParameters used by the unregistration command for revocation
214 * @param options the CommandOptions used by the unregistration command for revocation
215 * @param retryWaitTime the current wait time before retrying propagation
216 */
217 void
218 startRevocation(const ndn::nfd::ControlParameters& parameters,
219 const ndn::nfd::CommandOptions& options,
220 time::seconds retryWaitTime);
221
222 /**
223 * @brief invoked when Rib::afterInsertEntry signal is emitted
224 *
225 * step1: if the local RIB prefix @param prefix is for local use only, return
226 * step2: if the local RIB prefix @param prefix is a hub prefix, invoke afterHubConnect
227 * step3: if no valid PrefixPropagationParameters can be found for the local RIB prefix
228 * @param prefix, or the propagated prefix has already been processed, return
229 * step4: invoke afterRibInsert
230 */
231 void
232 afterInsertRibEntry(const Name& prefix);
233
234 /**
235 * @brief invoked when Rib::afterEraseEntry signal is emitted
236 *
237 * step1: if local RIB prefix @param prefix is for local use only, return
238 * step2: if local RIB prefix @param prefix is a hub prefix, invoke afterHubDisconnect
239 * step3: if no valid PrefixPropagationParameters can be found for local RIB prefix
240 * @param prefix, or there are other local RIB prefixes can be covered by the propagated
241 * prefix, return
242 * step4: invoke afterRibErase
243 */
244 void
245 afterEraseRibEntry(const Name& prefix);
246
247PUBLIC_WITH_TESTS_ELSE_PRIVATE: // PropagatedEntry state changes
248 /**
249 * @brief invoked after rib insertion for non-hub prefixes
250 * @pre the PropagatedEntry is in RELEASED state
251 * @post the PropagatedEntry will be in NEW state
252 *
253 * @param parameters the ControlParameters used by registration commands for propagation
254 * @param options the CommandOptions used by registration commands for propagation
255 */
256 void
257 afterRibInsert(const ndn::nfd::ControlParameters& parameters,
258 const ndn::nfd::CommandOptions& options);
259
260 /**
261 * @brief invoked after rib deletion for non-hub prefixes
262 * @pre the PropagatedEntry is not in RELEASED state
263 * @post the PropagatedEntry will be in RELEASED state
264 *
265 * @param parameters the ControlParameters used by registration commands for propagation
266 * @param options the CommandOptions used by registration commands for propagation
267 */
268 void
269 afterRibErase(const ndn::nfd::ControlParameters& parameters,
270 const ndn::nfd::CommandOptions& options);
271
272 /**
273 * @brief invoked after the hub is connected
274 * @pre the PropagatedEntry is in NEW state or RELEASED state
275 * @post the PropagatedEntry will be in PROPAGATING state or keep in RELEASED state
276 *
277 * call redoPropagation for each propagated entry.
278 */
279 void
280 afterHubConnect();
281
282 /**
283 * @brief invoked after the hub is disconnected
284 * @pre the PropagatedEntry is not in NEW state
285 * @post the PropagatedEntry will be in NEW state or keep in RELEASED state
286 *
287 * for each propagated entry, switch its state to NEW and cancel its event.
288 */
289 void
290 afterHubDisconnect();
291
292 /**
293 * @brief invoked after propagation succeeds
294 * @pre the PropagatedEntry is in PROPAGATING state or RELEASED state
295 * @post the PropagatedEntry will be in PROPAGATED state or keep in RELEASED state
296 *
297 * If the PropagatedEntry does not exist (in RELEASED state), an unregistration command is
298 * sent immediately for revocation.
299 *
300 * If the PropagatedEntry is in PROPAGATING state, switch it to PROPAGATED, and schedule a
301 * refresh timer to redo propagation after a duration, which is configured at
302 * rib.auto_prefix_propagate.refresh_interval.
303 *
304 * Otherwise, make a copy of the ControlParameters @p parameters, unset its Cost field, and then
305 * invoke startRevocation with this new ControlParameters.
306 *
307 * @param parameters the ControlParameters used by the registration command for propagation
308 * @param options the CommandOptions used by the registration command for propagation
309 * @param refreshEvent the event of refreshing propagation
310 */
311 void
312 afterPropagateSucceed(const ndn::nfd::ControlParameters& parameters,
313 const ndn::nfd::CommandOptions& options,
314 const ndn::Scheduler::Event& refreshEvent);
315
316 /**
317 * @brief invoked after propagation fails.
318 * @pre the PropagatedEntry is in PROPAGATING state or RELEASED state
319 * @post the PropagatedEntry will be in PROPAGATE_FAIL state or keep in RELEASED state
320 *
321 * If the PropagatedEntry still exists, schedule a retry timer to redo propagation
322 * after a duration defined by current retry time @p retryWaitTime
323 *
324 * @param code error code.
325 * @param reason error reason in string.
326 * @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
332 afterPropagateFail(uint32_t code, const std::string& reason,
333 const ndn::nfd::ControlParameters& parameters,
334 const ndn::nfd::CommandOptions& options,
335 time::seconds retryWaitTime,
336 const ndn::Scheduler::Event& retryEvent);
337
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
346 * invoke startPropagation with this new ControlParameters.
347 *
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 *
360 * @param code error code.
361 * @param reason error reason in string.
362 * @param parameters the ControlParameters used by the unregistration command for revocation
363 * @param options the CommandOptions used by the unregistration command for revocation
364 */
365 void
366 afterRevokeFail(uint32_t code, const std::string& reason,
367 const ndn::nfd::ControlParameters& parameters,
368 const ndn::nfd::CommandOptions& options);
369
370 /**
371 * @brief invoked when the refresh timer is triggered.
372 * @pre the PropagatedEntry is in PROPAGATED state
373 * @post the PropagatedEntry will be in PROPAGATING state
374 *
375 * call redoPropagation to handle this refresh request
376 *
377 * @param parameters the ControlParameters used by registration commands for propagation
378 * @param options the CommandOptions used by registration commands for propagation
379 */
380 void
381 onRefreshTimer(const ndn::nfd::ControlParameters& parameters,
382 const ndn::nfd::CommandOptions& options);
383
384 /**
385 * @brief invoked when the retry timer is triggered.
386 * @pre the PropagatedEntry is in PROPAGATE_FAIL state
387 * @post the PropagatedEntry will be in PROPAGATING state
388 *
389 * call redoPropagation to handle this retry request
390 *
391 * @param parameters the ControlParameters used by registration commands for propagation
392 * @param options the CommandOptions used by registration commands for propagation
393 * @param retryWaitTime the current wait time before retrying propagation
394 */
395 void
396 onRetryTimer(const ndn::nfd::ControlParameters& parameters,
397 const ndn::nfd::CommandOptions& options,
398 time::seconds retryWaitTime);
399
400PUBLIC_WITH_TESTS_ELSE_PRIVATE:
401 ndn::nfd::Controller& m_nfdController;
402 ndn::KeyChain& m_keyChain;
403 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