blob: 0bc8d9e88e4e80ab794988bc7aaf85a281f2cf1a [file] [log] [blame]
Junxiao Shid3c792f2014-01-30 00:46:13 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Junxiao Shi8d843142016-07-11 22:42:42 +00003 * Copyright (c) 2014-2016, 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
42 * \param strategyName versioned strategy name
43 * \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
48 registerType(const Name& strategyName = S::STRATEGY_NAME)
49 {
50 Registry& registry = getRegistry();
51 BOOST_ASSERT(registry.count(strategyName) == 0);
52 registry[strategyName] = &make_unique<S, Forwarder&, const Name&>;
53 }
54
55 /** \return whether a strategy instance can be created from \p strategyName
56 * \param strategyName strategy name, may contain version
57 * \todo #3868 may contain parameters
58 * \note This function finds a strategy type using same rules as \p create ,
59 * but does not attempt to construct an instance.
60 */
61 static bool
62 canCreate(const Name& strategyName);
63
64 /** \return a strategy instance created from \p strategyName,
65 * \retval nullptr if !canCreate(strategyName)
66 * \todo #3868 throw std::invalid_argument strategy type constructor
67 * does not accept specified version or parameters
68 */
69 static unique_ptr<Strategy>
70 create(const Name& strategyName, Forwarder& forwarder);
71
72 /** \return registered versioned strategy names
73 */
74 static std::set<Name>
75 listRegistered();
76
77public: // constructor, destructor, strategy name
Junxiao Shie93d6a32014-09-07 16:13:22 -070078 /** \brief construct a strategy instance
79 * \param forwarder a reference to the Forwarder, used to enable actions and accessors.
80 * Strategy subclasses should pass this reference,
81 * and should not keep a reference themselves.
82 * \param name the strategy Name.
83 * It's recommended to include a version number as the last component.
84 */
Junxiao Shibb5105f2014-03-03 12:06:45 -070085 Strategy(Forwarder& forwarder, const Name& name);
Junxiao Shidbe71732014-02-21 22:23:28 -070086
Junxiao Shid3c792f2014-01-30 00:46:13 -070087 virtual
88 ~Strategy();
Junxiao Shidbe71732014-02-21 22:23:28 -070089
Junxiao Shib9420cf2016-08-13 04:38:52 +000090 /** \return a Name that represents the strategy program
91 */
Junxiao Shibb5105f2014-03-03 12:06:45 -070092 const Name&
Junxiao Shib9420cf2016-08-13 04:38:52 +000093 getName() const
94 {
95 return m_name;
96 }
Junxiao Shibb5105f2014-03-03 12:06:45 -070097
Junxiao Shi679e9272014-02-15 20:10:21 -070098public: // triggers
99 /** \brief trigger after Interest is received
100 *
101 * The Interest:
102 * - does not violate Scope
103 * - is not looped
104 * - cannot be satisfied by ContentStore
105 * - is under a namespace managed by this strategy
106 *
107 * The strategy should decide whether and where to forward this Interest.
108 * - If the strategy decides to forward this Interest,
109 * invoke this->sendInterest one or more times, either now or shortly after
110 * - If strategy concludes that this Interest cannot be forwarded,
Junxiao Shi09498f02014-02-26 19:41:08 -0700111 * invoke this->rejectPendingInterest so that PIT entry will be deleted shortly
Junxiao Shi82e7f582014-09-07 15:15:40 -0700112 *
Junxiao Shi15e98b02016-08-12 11:21:44 +0000113 * \warning The strategy must not retain shared_ptr<pit::Entry>, otherwise undefined behavior
114 * may occur. However, the strategy is allowed to store weak_ptr<pit::Entry>.
Junxiao Shi679e9272014-02-15 20:10:21 -0700115 */
Junxiao Shid3c792f2014-01-30 00:46:13 -0700116 virtual void
Junxiao Shi8d843142016-07-11 22:42:42 +0000117 afterReceiveInterest(const Face& inFace, const Interest& interest,
Junxiao Shi15e98b02016-08-12 11:21:44 +0000118 const shared_ptr<pit::Entry>& pitEntry) = 0;
Junxiao Shidbe71732014-02-21 22:23:28 -0700119
Junxiao Shi22be22c2014-02-16 22:53:48 -0700120 /** \brief trigger before PIT entry is satisfied
121 *
Junxiao Shi82e7f582014-09-07 15:15:40 -0700122 * This trigger is invoked when an incoming Data satisfies the PIT entry.
123 * It can be invoked even if the PIT entry has already been satisfied.
124 *
Junxiao Shi22be22c2014-02-16 22:53:48 -0700125 * In this base class this method does nothing.
Junxiao Shi82e7f582014-09-07 15:15:40 -0700126 *
Junxiao Shi15e98b02016-08-12 11:21:44 +0000127 * \warning The strategy must not retain shared_ptr<pit::Entry>, otherwise undefined behavior
128 * may occur. However, the strategy is allowed to store weak_ptr<pit::Entry>.
Junxiao Shi22be22c2014-02-16 22:53:48 -0700129 */
130 virtual void
Junxiao Shi15e98b02016-08-12 11:21:44 +0000131 beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
Junxiao Shi82e7f582014-09-07 15:15:40 -0700132 const Face& inFace, const Data& data);
Junxiao Shidbe71732014-02-21 22:23:28 -0700133
Junxiao Shi679e9272014-02-15 20:10:21 -0700134 /** \brief trigger before PIT entry expires
135 *
136 * PIT entry expires when InterestLifetime has elapsed for all InRecords,
137 * and it is not satisfied by an incoming Data.
138 *
139 * This trigger is not invoked for PIT entry already satisfied.
140 *
141 * In this base class this method does nothing.
Junxiao Shi82e7f582014-09-07 15:15:40 -0700142 *
Junxiao Shi15e98b02016-08-12 11:21:44 +0000143 * \warning The strategy must not retain shared_ptr<pit::Entry>, otherwise undefined behavior
144 * may occur. However, the strategy is allowed to store weak_ptr<pit::Entry>,
145 * although this isn't useful here because PIT entry would be deleted shortly after.
Junxiao Shi679e9272014-02-15 20:10:21 -0700146 */
147 virtual void
Junxiao Shi15e98b02016-08-12 11:21:44 +0000148 beforeExpirePendingInterest(const shared_ptr<pit::Entry>& pitEntry);
Junxiao Shidbe71732014-02-21 22:23:28 -0700149
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700150 /** \brief trigger after Nack is received
151 *
152 * This trigger is invoked when an incoming Nack is received in response to
153 * an forwarded Interest.
154 * The Nack has been confirmed to be a response to the last Interest forwarded
155 * to that upstream, i.e. the PIT out-record exists and has a matching Nonce.
156 * The NackHeader has been recorded in the PIT out-record.
157 *
158 * In this base class this method does nothing.
159 *
Junxiao Shi15e98b02016-08-12 11:21:44 +0000160 * \warning The strategy must not retain shared_ptr<pit::Entry>, otherwise undefined behavior
161 * may occur. However, the strategy is allowed to store weak_ptr<pit::Entry>.
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700162 */
163 virtual void
164 afterReceiveNack(const Face& inFace, const lp::Nack& nack,
Junxiao Shi15e98b02016-08-12 11:21:44 +0000165 const shared_ptr<pit::Entry>& pitEntry);
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700166
Junxiao Shid3c792f2014-01-30 00:46:13 -0700167protected: // actions
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700168 /** \brief send Interest to outFace
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -0500169 * \param pitEntry PIT entry
170 * \param outFace face through which to send out the Interest
Junxiao Shic5f651f2016-11-17 22:58:12 +0000171 * \param interest the Interest packet
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700172 */
Junxiao Shi727ed292014-02-19 23:26:45 -0700173 VIRTUAL_WITH_TESTS void
Junxiao Shib9420cf2016-08-13 04:38:52 +0000174 sendInterest(const shared_ptr<pit::Entry>& pitEntry, Face& outFace,
Junxiao Shic5f651f2016-11-17 22:58:12 +0000175 const Interest& interest)
Junxiao Shib9420cf2016-08-13 04:38:52 +0000176 {
Junxiao Shic5f651f2016-11-17 22:58:12 +0000177 m_forwarder.onOutgoingInterest(pitEntry, outFace, interest);
Junxiao Shib9420cf2016-08-13 04:38:52 +0000178 }
Junxiao Shidbe71732014-02-21 22:23:28 -0700179
Junxiao Shid3c792f2014-01-30 00:46:13 -0700180 /** \brief decide that a pending Interest cannot be forwarded
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -0500181 * \param pitEntry PIT entry
Junxiao Shi679e9272014-02-15 20:10:21 -0700182 *
Junxiao Shid3c792f2014-01-30 00:46:13 -0700183 * This shall not be called if the pending Interest has been
184 * forwarded earlier, and does not need to be resent now.
185 */
Junxiao Shi727ed292014-02-19 23:26:45 -0700186 VIRTUAL_WITH_TESTS void
Junxiao Shib9420cf2016-08-13 04:38:52 +0000187 rejectPendingInterest(const shared_ptr<pit::Entry>& pitEntry)
188 {
189 m_forwarder.onInterestReject(pitEntry);
190 }
Junxiao Shidbe71732014-02-21 22:23:28 -0700191
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700192 /** \brief send Nack to outFace
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -0500193 * \param pitEntry PIT entry
194 * \param outFace face through which to send out the Nack
195 * \param header Nack header
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700196 *
197 * The outFace must have a PIT in-record, otherwise this method has no effect.
198 */
199 VIRTUAL_WITH_TESTS void
Junxiao Shib9420cf2016-08-13 04:38:52 +0000200 sendNack(const shared_ptr<pit::Entry>& pitEntry, const Face& outFace,
201 const lp::NackHeader& header)
202 {
203 m_forwarder.onOutgoingNack(pitEntry, outFace, header);
204 }
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700205
206 /** \brief send Nack to every face that has an in-record,
207 * except those in \p exceptFaces
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -0500208 * \param pitEntry PIT entry
209 * \param header NACK header
210 * \param exceptFaces list of faces that should be excluded from sending Nacks
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700211 * \note This is not an action, but a helper that invokes the sendNack action.
212 */
213 void
Junxiao Shib9420cf2016-08-13 04:38:52 +0000214 sendNacks(const shared_ptr<pit::Entry>& pitEntry, const lp::NackHeader& header,
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700215 std::initializer_list<const Face*> exceptFaces = std::initializer_list<const Face*>());
216
Junxiao Shidbe71732014-02-21 22:23:28 -0700217protected: // accessors
Junxiao Shicf0f3ce2016-09-02 13:01:59 +0000218 /** \brief performs a FIB lookup, considering Link object if present
219 */
Junxiao Shi8d843142016-07-11 22:42:42 +0000220 const fib::Entry&
Junxiao Shicf0f3ce2016-09-02 13:01:59 +0000221 lookupFib(const pit::Entry& pitEntry) const;
Junxiao Shi8d843142016-07-11 22:42:42 +0000222
Junxiao Shidbe71732014-02-21 22:23:28 -0700223 MeasurementsAccessor&
Junxiao Shib9420cf2016-08-13 04:38:52 +0000224 getMeasurements()
225 {
226 return m_measurements;
227 }
Junxiao Shidbe71732014-02-21 22:23:28 -0700228
Junxiao Shi5b43f9a2016-07-19 13:15:56 +0000229 Face*
Junxiao Shib9420cf2016-08-13 04:38:52 +0000230 getFace(FaceId id) const
231 {
232 return m_forwarder.getFace(id);
233 }
Junxiao Shi2d9bdc82014-03-02 20:55:42 -0700234
Junxiao Shi49e11e72014-12-14 19:46:05 -0700235 const FaceTable&
Junxiao Shib9420cf2016-08-13 04:38:52 +0000236 getFaceTable() const
237 {
238 return m_forwarder.getFaceTable();
239 }
Junxiao Shi49e11e72014-12-14 19:46:05 -0700240
241protected: // accessors
Junxiao Shiae04d342016-07-19 13:20:22 +0000242 signal::Signal<FaceTable, Face&>& afterAddFace;
243 signal::Signal<FaceTable, Face&>& beforeRemoveFace;
Junxiao Shi49e11e72014-12-14 19:46:05 -0700244
Junxiao Shic34d1672016-12-09 15:57:59 +0000245private: // registry
246 typedef std::function<unique_ptr<Strategy>(Forwarder& forwarder, const Name& strategyName)> CreateFunc;
247 typedef std::map<Name, CreateFunc> Registry; // indexed by strategy name
248
249 static Registry&
250 getRegistry();
251
252 static Registry::const_iterator
253 find(const Name& strategyName);
254
255private: // instance fields
Junxiao Shibb5105f2014-03-03 12:06:45 -0700256 Name m_name;
257
Junxiao Shi679e9272014-02-15 20:10:21 -0700258 /** \brief reference to the forwarder
259 *
260 * Triggers can access forwarder indirectly via actions.
261 */
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700262 Forwarder& m_forwarder;
Junxiao Shidbe71732014-02-21 22:23:28 -0700263
264 MeasurementsAccessor m_measurements;
Junxiao Shid3c792f2014-01-30 00:46:13 -0700265};
266
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700267} // namespace fw
Junxiao Shid3c792f2014-01-30 00:46:13 -0700268} // namespace nfd
269
Junxiao Shic34d1672016-12-09 15:57:59 +0000270/** \brief registers a strategy
271 *
272 * This macro should appear once in .cpp of each strategy.
273 */
274#define NFD_REGISTER_STRATEGY(S) \
275static class NfdAuto ## S ## StrategyRegistrationClass \
276{ \
277public: \
278 NfdAuto ## S ## StrategyRegistrationClass() \
279 { \
280 ::nfd::fw::Strategy::registerType<S>(); \
281 } \
282} g_nfdAuto ## S ## StrategyRegistrationVariable
283
Alexander Afanasyev613e2a92014-04-15 13:36:58 -0700284#endif // NFD_DAEMON_FW_STRATEGY_HPP