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