blob: e770e27119a409f17906d2f8eb261a3ce97b7939 [file] [log] [blame]
Junxiao Shid3c792f2014-01-30 00:46:13 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Eric Newberry41aba102017-11-01 16:42:13 -07002/*
Teng Liang63086442018-02-25 20:39:42 -07003 * Copyright (c) 2014-2018, Regents of the University of California,
Junxiao Shifaf3eb02015-02-16 10:50:36 -07004 * 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.
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -070010 *
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/>.
Junxiao Shi82e7f582014-09-07 15:15:40 -070024 */
Junxiao Shid3c792f2014-01-30 00:46:13 -070025
Alexander Afanasyev613e2a92014-04-15 13:36:58 -070026#ifndef NFD_DAEMON_FW_STRATEGY_HPP
27#define NFD_DAEMON_FW_STRATEGY_HPP
Junxiao Shid3c792f2014-01-30 00:46:13 -070028
Junxiao Shi2d9bdc82014-03-02 20:55:42 -070029#include "forwarder.hpp"
Junxiao Shidbe71732014-02-21 22:23:28 -070030#include "table/measurements-accessor.hpp"
Junxiao Shid3c792f2014-01-30 00:46:13 -070031
32namespace nfd {
Junxiao Shi8c8d2182014-01-30 22:33:00 -070033namespace fw {
34
Junxiao Shibb5105f2014-03-03 12:06:45 -070035/** \brief represents a forwarding strategy
Junxiao Shid3c792f2014-01-30 00:46:13 -070036 */
Junxiao Shic34d1672016-12-09 15:57:59 +000037class Strategy : noncopyable
Junxiao Shid3c792f2014-01-30 00:46:13 -070038{
Junxiao Shic34d1672016-12-09 15:57:59 +000039public: // registry
40 /** \brief register a strategy type
41 * \tparam S subclass of Strategy
Junxiao Shi18739c42016-12-22 08:03:00 +000042 * \param strategyName strategy program name, must contain version
Junxiao Shic34d1672016-12-09 15:57:59 +000043 * \note It is permitted to register the same strategy type under multiple names,
44 * which is useful in tests and for creating aliases.
45 */
46 template<typename S>
47 static void
Junxiao Shi037f4ab2016-12-13 04:27:06 +000048 registerType(const Name& strategyName = S::getStrategyName())
Junxiao Shic34d1672016-12-09 15:57:59 +000049 {
Junxiao Shi91f6ee02016-12-29 21:44:44 +000050 BOOST_ASSERT(strategyName.size() > 1);
Junxiao Shi18739c42016-12-22 08:03:00 +000051 BOOST_ASSERT(strategyName.at(-1).isVersion());
Junxiao Shic34d1672016-12-09 15:57:59 +000052 Registry& registry = getRegistry();
53 BOOST_ASSERT(registry.count(strategyName) == 0);
54 registry[strategyName] = &make_unique<S, Forwarder&, const Name&>;
55 }
56
Junxiao Shi18739c42016-12-22 08:03:00 +000057 /** \return whether a strategy instance can be created from \p instanceName
58 * \param instanceName strategy instance name, may contain version and parameters
Junxiao Shic34d1672016-12-09 15:57:59 +000059 * \note This function finds a strategy type using same rules as \p create ,
60 * but does not attempt to construct an instance.
61 */
62 static bool
Junxiao Shi18739c42016-12-22 08:03:00 +000063 canCreate(const Name& instanceName);
Junxiao Shic34d1672016-12-09 15:57:59 +000064
Junxiao Shi18739c42016-12-22 08:03:00 +000065 /** \return a strategy instance created from \p instanceName
66 * \retval nullptr if !canCreate(instanceName)
67 * \throw std::invalid_argument strategy type constructor does not accept
68 * specified version or parameters
Junxiao Shic34d1672016-12-09 15:57:59 +000069 */
70 static unique_ptr<Strategy>
Junxiao Shi18739c42016-12-22 08:03:00 +000071 create(const Name& instanceName, Forwarder& forwarder);
Junxiao Shic34d1672016-12-09 15:57:59 +000072
Junxiao Shi55e21b92017-01-23 03:27:47 +000073 /** \return whether \p instanceNameA and \p instanceNameA will initiate same strategy type
74 */
75 static bool
76 areSameType(const Name& instanceNameA, const Name& instanceNameB);
77
Junxiao Shic34d1672016-12-09 15:57:59 +000078 /** \return registered versioned strategy names
79 */
80 static std::set<Name>
81 listRegistered();
82
83public: // constructor, destructor, strategy name
Junxiao Shie93d6a32014-09-07 16:13:22 -070084 /** \brief construct a strategy instance
Junxiao Shi18739c42016-12-22 08:03:00 +000085 * \param forwarder a reference to the forwarder, used to enable actions and accessors.
86 * \note Strategy subclass constructor should not retain a reference to the forwarder.
Junxiao Shie93d6a32014-09-07 16:13:22 -070087 */
Junxiao Shi18739c42016-12-22 08:03:00 +000088 explicit
89 Strategy(Forwarder& forwarder);
Junxiao Shidbe71732014-02-21 22:23:28 -070090
Junxiao Shid3c792f2014-01-30 00:46:13 -070091 virtual
92 ~Strategy();
Junxiao Shidbe71732014-02-21 22:23:28 -070093
Junxiao Shi037f4ab2016-12-13 04:27:06 +000094#ifdef DOXYGEN
Junxiao Shi18739c42016-12-22 08:03:00 +000095 /** \return strategy program name
96 *
97 * The strategy name is defined by the strategy program.
98 * It must end with a version component.
Junxiao Shi037f4ab2016-12-13 04:27:06 +000099 */
100 static const Name&
101 getStrategyName();
102#endif
103
Junxiao Shi18739c42016-12-22 08:03:00 +0000104 /** \return strategy instance name
105 *
106 * The instance name is assigned during instantiation.
107 * It contains a version component, and may have extra parameter components.
Junxiao Shib9420cf2016-08-13 04:38:52 +0000108 */
Junxiao Shibb5105f2014-03-03 12:06:45 -0700109 const Name&
Junxiao Shi18739c42016-12-22 08:03:00 +0000110 getInstanceName() const
Junxiao Shib9420cf2016-08-13 04:38:52 +0000111 {
112 return m_name;
113 }
Junxiao Shibb5105f2014-03-03 12:06:45 -0700114
Junxiao Shi679e9272014-02-15 20:10:21 -0700115public: // triggers
116 /** \brief trigger after Interest is received
117 *
118 * The Interest:
119 * - does not violate Scope
120 * - is not looped
121 * - cannot be satisfied by ContentStore
122 * - is under a namespace managed by this strategy
123 *
Teng Liang7003e0b2018-03-03 16:03:30 -0700124 * The PIT entry is set to expire after InterestLifetime has elapsed at each downstream.
125 *
Junxiao Shi679e9272014-02-15 20:10:21 -0700126 * The strategy should decide whether and where to forward this Interest.
127 * - If the strategy decides to forward this Interest,
Teng Liang7003e0b2018-03-03 16:03:30 -0700128 * invoke \c sendInterest for each upstream, either now or shortly after via a scheduler event,
129 * but before PIT entry expires.
130 * Optionally, the strategy can invoke \c setExpiryTimer to adjust how long it would wait for a response.
131 * - If the strategy has already forwarded this Interest previously and decides to continue waiting,
132 * do nothing.
133 * Optionally, the strategy can invoke \c setExpiryTimer to adjust how long it would wait for a response.
134 * - If the strategy concludes that this Interest cannot be satisfied,
135 * invoke \c rejectPendingInterest to erase the PIT entry.
Junxiao Shi82e7f582014-09-07 15:15:40 -0700136 *
Junxiao Shi15e98b02016-08-12 11:21:44 +0000137 * \warning The strategy must not retain shared_ptr<pit::Entry>, otherwise undefined behavior
138 * may occur. However, the strategy is allowed to store weak_ptr<pit::Entry>.
Junxiao Shi679e9272014-02-15 20:10:21 -0700139 */
Junxiao Shid3c792f2014-01-30 00:46:13 -0700140 virtual void
Junxiao Shi8d843142016-07-11 22:42:42 +0000141 afterReceiveInterest(const Face& inFace, const Interest& interest,
Junxiao Shi15e98b02016-08-12 11:21:44 +0000142 const shared_ptr<pit::Entry>& pitEntry) = 0;
Junxiao Shidbe71732014-02-21 22:23:28 -0700143
Junxiao Shi22be22c2014-02-16 22:53:48 -0700144 /** \brief trigger before PIT entry is satisfied
145 *
Junxiao Shi82e7f582014-09-07 15:15:40 -0700146 * This trigger is invoked when an incoming Data satisfies the PIT entry.
Teng Liang7003e0b2018-03-03 16:03:30 -0700147 * Normally, only the first incoming Data would satisfy the PIT entry and invoke this trigger,
148 * after which the PIT entry is erased.
149 *
150 * If the strategy wishes to collect responses from additional upstream nodes,
151 * it should invoke \c setExpiryTimer within this function to retain the PIT entry.
152 * If a Data arrives from another upstream during the extended PIT entry lifetime, this trigger will be invoked again.
153 * At that time, this function must invoke \c setExpiryTimer again to continue collecting more responses.
Junxiao Shi82e7f582014-09-07 15:15:40 -0700154 *
Junxiao Shi22be22c2014-02-16 22:53:48 -0700155 * In this base class this method does nothing.
Junxiao Shi82e7f582014-09-07 15:15:40 -0700156 *
Junxiao Shi15e98b02016-08-12 11:21:44 +0000157 * \warning The strategy must not retain shared_ptr<pit::Entry>, otherwise undefined behavior
158 * may occur. However, the strategy is allowed to store weak_ptr<pit::Entry>.
Junxiao Shi22be22c2014-02-16 22:53:48 -0700159 */
160 virtual void
Junxiao Shi15e98b02016-08-12 11:21:44 +0000161 beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
Junxiao Shi82e7f582014-09-07 15:15:40 -0700162 const Face& inFace, const Data& data);
Junxiao Shidbe71732014-02-21 22:23:28 -0700163
Teng Liang85a36632018-03-21 05:59:34 -0700164 /** \brief trigger after a Data is matched in CS
165 *
166 * In the base class this method sends \p data to \p inFace
167 */
168 virtual void
169 afterContentStoreHit(const shared_ptr<pit::Entry>& pitEntry,
170 const Face& inFace, const Data& data);
171
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700172 /** \brief trigger after Nack is received
173 *
174 * This trigger is invoked when an incoming Nack is received in response to
175 * an forwarded Interest.
176 * The Nack has been confirmed to be a response to the last Interest forwarded
177 * to that upstream, i.e. the PIT out-record exists and has a matching Nonce.
178 * The NackHeader has been recorded in the PIT out-record.
179 *
Teng Liang7003e0b2018-03-03 16:03:30 -0700180 * If the PIT entry is not yet satisfied, its expiry timer remains unchanged.
181 * Otherwise, the PIT entry normally would expire immediately after this function returns.
182 *
183 * If the strategy wishes to collect responses from additional upstream nodes,
184 * it should invoke \c setExpiryTimer within this function to retain the PIT entry.
185 * If a Nack arrives from another upstream during the extended PIT entry lifetime, this trigger will be invoked again.
186 * At that time, this function must invoke \c setExpiryTimer again to continue collecting more responses.
187 *
Teng Liang85a36632018-03-21 05:59:34 -0700188 * In the base class this method does nothing.
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700189 *
Junxiao Shi15e98b02016-08-12 11:21:44 +0000190 * \warning The strategy must not retain shared_ptr<pit::Entry>, otherwise undefined behavior
191 * may occur. However, the strategy is allowed to store weak_ptr<pit::Entry>.
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700192 */
193 virtual void
194 afterReceiveNack(const Face& inFace, const lp::Nack& nack,
Junxiao Shi15e98b02016-08-12 11:21:44 +0000195 const shared_ptr<pit::Entry>& pitEntry);
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700196
Eric Newberry41aba102017-11-01 16:42:13 -0700197 /** \brief trigger after Interest dropped for exceeding allowed retransmissions
198 *
199 * In the base class this method does nothing.
200 */
201 virtual void
202 onDroppedInterest(const Face& outFace, const Interest& interest);
203
Junxiao Shid3c792f2014-01-30 00:46:13 -0700204protected: // actions
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700205 /** \brief send Interest to outFace
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -0500206 * \param pitEntry PIT entry
207 * \param outFace face through which to send out the Interest
Junxiao Shic5f651f2016-11-17 22:58:12 +0000208 * \param interest the Interest packet
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700209 */
Junxiao Shi727ed292014-02-19 23:26:45 -0700210 VIRTUAL_WITH_TESTS void
Junxiao Shib9420cf2016-08-13 04:38:52 +0000211 sendInterest(const shared_ptr<pit::Entry>& pitEntry, Face& outFace,
Junxiao Shic5f651f2016-11-17 22:58:12 +0000212 const Interest& interest)
Junxiao Shib9420cf2016-08-13 04:38:52 +0000213 {
Junxiao Shic5f651f2016-11-17 22:58:12 +0000214 m_forwarder.onOutgoingInterest(pitEntry, outFace, interest);
Junxiao Shib9420cf2016-08-13 04:38:52 +0000215 }
Junxiao Shidbe71732014-02-21 22:23:28 -0700216
Teng Liang85a36632018-03-21 05:59:34 -0700217 /** \brief send \p data to \p outFace
218 * \param pitEntry PIT entry
219 * \param data the Data packet
220 * \param outFace face through which to send out the Data
221 */
222 VIRTUAL_WITH_TESTS void
223 sendData(const shared_ptr<pit::Entry>& pitEntry, const Data& data, const Face& outFace)
224 {
225 BOOST_ASSERT(pitEntry->getInterest().matchesData(data));
226
227 m_forwarder.onOutgoingData(data, *const_pointer_cast<Face>(outFace.shared_from_this()));
228 }
229
Teng Liang7003e0b2018-03-03 16:03:30 -0700230 /** \brief schedule the PIT entry for immediate deletion
Junxiao Shi679e9272014-02-15 20:10:21 -0700231 *
Teng Liang7003e0b2018-03-03 16:03:30 -0700232 * This helper function sets the PIT entry expiry time to zero.
233 * The strategy should invoke this function when it concludes that the Interest cannot
234 * be forwarded and it does not want to wait for responses from existing upstream nodes.
Junxiao Shid3c792f2014-01-30 00:46:13 -0700235 */
Junxiao Shi727ed292014-02-19 23:26:45 -0700236 VIRTUAL_WITH_TESTS void
Junxiao Shib9420cf2016-08-13 04:38:52 +0000237 rejectPendingInterest(const shared_ptr<pit::Entry>& pitEntry)
238 {
Teng Liang7003e0b2018-03-03 16:03:30 -0700239 this->setExpiryTimer(pitEntry, 0_ms);
Junxiao Shib9420cf2016-08-13 04:38:52 +0000240 }
Junxiao Shidbe71732014-02-21 22:23:28 -0700241
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700242 /** \brief send Nack to outFace
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -0500243 * \param pitEntry PIT entry
244 * \param outFace face through which to send out the Nack
245 * \param header Nack header
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700246 *
247 * The outFace must have a PIT in-record, otherwise this method has no effect.
248 */
249 VIRTUAL_WITH_TESTS void
Junxiao Shib9420cf2016-08-13 04:38:52 +0000250 sendNack(const shared_ptr<pit::Entry>& pitEntry, const Face& outFace,
251 const lp::NackHeader& header)
252 {
253 m_forwarder.onOutgoingNack(pitEntry, outFace, header);
254 }
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700255
256 /** \brief send Nack to every face that has an in-record,
257 * except those in \p exceptFaces
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -0500258 * \param pitEntry PIT entry
259 * \param header NACK header
260 * \param exceptFaces list of faces that should be excluded from sending Nacks
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700261 * \note This is not an action, but a helper that invokes the sendNack action.
262 */
263 void
Junxiao Shib9420cf2016-08-13 04:38:52 +0000264 sendNacks(const shared_ptr<pit::Entry>& pitEntry, const lp::NackHeader& header,
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700265 std::initializer_list<const Face*> exceptFaces = std::initializer_list<const Face*>());
266
Teng Liang7003e0b2018-03-03 16:03:30 -0700267 /** \brief Schedule the PIT entry to be erased after \p duration
268 */
269 void
270 setExpiryTimer(const shared_ptr<pit::Entry>& pitEntry, time::milliseconds duration)
271 {
272 m_forwarder.setExpiryTimer(pitEntry, duration);
273 }
274
Junxiao Shidbe71732014-02-21 22:23:28 -0700275protected: // accessors
Junxiao Shicf0f3ce2016-09-02 13:01:59 +0000276 /** \brief performs a FIB lookup, considering Link object if present
277 */
Junxiao Shi8d843142016-07-11 22:42:42 +0000278 const fib::Entry&
Junxiao Shicf0f3ce2016-09-02 13:01:59 +0000279 lookupFib(const pit::Entry& pitEntry) const;
Junxiao Shi8d843142016-07-11 22:42:42 +0000280
Junxiao Shidbe71732014-02-21 22:23:28 -0700281 MeasurementsAccessor&
Junxiao Shib9420cf2016-08-13 04:38:52 +0000282 getMeasurements()
283 {
284 return m_measurements;
285 }
Junxiao Shidbe71732014-02-21 22:23:28 -0700286
Junxiao Shi5b43f9a2016-07-19 13:15:56 +0000287 Face*
Junxiao Shib9420cf2016-08-13 04:38:52 +0000288 getFace(FaceId id) const
289 {
290 return m_forwarder.getFace(id);
291 }
Junxiao Shi2d9bdc82014-03-02 20:55:42 -0700292
Junxiao Shi49e11e72014-12-14 19:46:05 -0700293 const FaceTable&
Junxiao Shib9420cf2016-08-13 04:38:52 +0000294 getFaceTable() const
295 {
296 return m_forwarder.getFaceTable();
297 }
Junxiao Shi49e11e72014-12-14 19:46:05 -0700298
Junxiao Shi18739c42016-12-22 08:03:00 +0000299protected: // instance name
300 struct ParsedInstanceName
301 {
302 Name strategyName; ///< strategy name without parameters
303 ndn::optional<uint64_t> version; ///< whether strategyName contains a version component
304 PartialName parameters; ///< parameter components
305 };
306
307 /** \brief parse a strategy instance name
308 * \param input strategy instance name, may contain version and parameters
309 * \throw std::invalid_argument input format is unacceptable
310 */
311 static ParsedInstanceName
312 parseInstanceName(const Name& input);
313
314 /** \brief construct a strategy instance name
315 * \param input strategy instance name, may contain version and parameters
316 * \param strategyName strategy name with version but without parameters;
317 * typically this should be \p getStrategyName()
318 *
319 * If \p input contains a version component, return \p input unchanged.
320 * Otherwise, return \p input plus the version component taken from \p strategyName.
321 * This allows a strategy instance to be constructed with an unversioned name,
322 * but its final instance name should contain the version.
323 */
324 static Name
325 makeInstanceName(const Name& input, const Name& strategyName);
326
327 /** \brief set strategy instance name
328 * \note This must be called by strategy subclass constructor.
329 */
330 void
331 setInstanceName(const Name& name)
332 {
333 m_name = name;
334 }
Junxiao Shi49e11e72014-12-14 19:46:05 -0700335
Junxiao Shic34d1672016-12-09 15:57:59 +0000336private: // registry
337 typedef std::function<unique_ptr<Strategy>(Forwarder& forwarder, const Name& strategyName)> CreateFunc;
338 typedef std::map<Name, CreateFunc> Registry; // indexed by strategy name
339
340 static Registry&
341 getRegistry();
342
343 static Registry::const_iterator
Junxiao Shi18739c42016-12-22 08:03:00 +0000344 find(const Name& instanceName);
345
346protected: // accessors
347 signal::Signal<FaceTable, Face&>& afterAddFace;
348 signal::Signal<FaceTable, Face&>& beforeRemoveFace;
Junxiao Shic34d1672016-12-09 15:57:59 +0000349
350private: // instance fields
Junxiao Shibb5105f2014-03-03 12:06:45 -0700351 Name m_name;
352
Junxiao Shi679e9272014-02-15 20:10:21 -0700353 /** \brief reference to the forwarder
354 *
355 * Triggers can access forwarder indirectly via actions.
356 */
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700357 Forwarder& m_forwarder;
Junxiao Shidbe71732014-02-21 22:23:28 -0700358
359 MeasurementsAccessor m_measurements;
Junxiao Shid3c792f2014-01-30 00:46:13 -0700360};
361
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700362} // namespace fw
Junxiao Shid3c792f2014-01-30 00:46:13 -0700363} // namespace nfd
364
Junxiao Shic34d1672016-12-09 15:57:59 +0000365/** \brief registers a strategy
366 *
367 * This macro should appear once in .cpp of each strategy.
368 */
369#define NFD_REGISTER_STRATEGY(S) \
370static class NfdAuto ## S ## StrategyRegistrationClass \
371{ \
372public: \
373 NfdAuto ## S ## StrategyRegistrationClass() \
374 { \
375 ::nfd::fw::Strategy::registerType<S>(); \
376 } \
377} g_nfdAuto ## S ## StrategyRegistrationVariable
378
Alexander Afanasyev613e2a92014-04-15 13:36:58 -0700379#endif // NFD_DAEMON_FW_STRATEGY_HPP