blob: 570f2194b4a8ca93b16aab86716473a2a076e1df [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/*
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -04003 * Copyright (c) 2014-2022, 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
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -040035class StrategyParameters;
36
Davide Pesavento0498ce82021-06-14 02:02:21 -040037/**
38 * \brief Represents a forwarding strategy
Junxiao Shid3c792f2014-01-30 00:46:13 -070039 */
Junxiao Shic34d1672016-12-09 15:57:59 +000040class Strategy : noncopyable
Junxiao Shid3c792f2014-01-30 00:46:13 -070041{
Junxiao Shic34d1672016-12-09 15:57:59 +000042public: // registry
Eric Newberryc68b2e82020-04-16 12:40:30 -070043 /** \brief Register a strategy type
Junxiao Shic34d1672016-12-09 15:57:59 +000044 * \tparam S subclass of Strategy
Junxiao Shi18739c42016-12-22 08:03:00 +000045 * \param strategyName strategy program name, must contain version
Junxiao Shic34d1672016-12-09 15:57:59 +000046 * \note It is permitted to register the same strategy type under multiple names,
47 * which is useful in tests and for creating aliases.
48 */
49 template<typename S>
50 static void
Junxiao Shi037f4ab2016-12-13 04:27:06 +000051 registerType(const Name& strategyName = S::getStrategyName())
Junxiao Shic34d1672016-12-09 15:57:59 +000052 {
Junxiao Shi91f6ee02016-12-29 21:44:44 +000053 BOOST_ASSERT(strategyName.size() > 1);
Junxiao Shi18739c42016-12-22 08:03:00 +000054 BOOST_ASSERT(strategyName.at(-1).isVersion());
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -040055 auto r = getRegistry().insert_or_assign(strategyName, [] (auto&&... args) {
Davide Pesavento3dade002019-03-19 11:29:56 -060056 return make_unique<S>(std::forward<decltype(args)>(args)...);
Davide Pesaventoa3a7a4e2022-05-29 16:06:22 -040057 });
58 BOOST_VERIFY(r.second);
Junxiao Shic34d1672016-12-09 15:57:59 +000059 }
60
Eric Newberryc68b2e82020-04-16 12:40:30 -070061 /** \return Whether a strategy instance can be created from \p instanceName
Junxiao Shi18739c42016-12-22 08:03:00 +000062 * \param instanceName strategy instance name, may contain version and parameters
Junxiao Shic34d1672016-12-09 15:57:59 +000063 * \note This function finds a strategy type using same rules as \p create ,
64 * but does not attempt to construct an instance.
65 */
66 static bool
Junxiao Shi18739c42016-12-22 08:03:00 +000067 canCreate(const Name& instanceName);
Junxiao Shic34d1672016-12-09 15:57:59 +000068
Eric Newberryc68b2e82020-04-16 12:40:30 -070069 /** \return A strategy instance created from \p instanceName
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -040070 * \retval nullptr if `canCreate(instanceName) == false`
Junxiao Shi18739c42016-12-22 08:03:00 +000071 * \throw std::invalid_argument strategy type constructor does not accept
72 * specified version or parameters
Junxiao Shic34d1672016-12-09 15:57:59 +000073 */
74 static unique_ptr<Strategy>
Junxiao Shi18739c42016-12-22 08:03:00 +000075 create(const Name& instanceName, Forwarder& forwarder);
Junxiao Shic34d1672016-12-09 15:57:59 +000076
Eric Newberryc68b2e82020-04-16 12:40:30 -070077 /** \return Whether \p instanceNameA and \p instanceNameA will initiate same strategy type
Junxiao Shi55e21b92017-01-23 03:27:47 +000078 */
79 static bool
80 areSameType(const Name& instanceNameA, const Name& instanceNameB);
81
Eric Newberryc68b2e82020-04-16 12:40:30 -070082 /** \return Registered versioned strategy names
Junxiao Shic34d1672016-12-09 15:57:59 +000083 */
84 static std::set<Name>
85 listRegistered();
86
Ju Pan2feb4592019-09-16 20:56:38 +000087public: // constructor, destructor, strategy info
Davide Pesavento3dade002019-03-19 11:29:56 -060088 /** \brief Construct a strategy instance.
Junxiao Shi18739c42016-12-22 08:03:00 +000089 * \param forwarder a reference to the forwarder, used to enable actions and accessors.
Davide Pesavento3dade002019-03-19 11:29:56 -060090 * \note Strategy subclass constructor must not retain a reference to \p forwarder.
Junxiao Shie93d6a32014-09-07 16:13:22 -070091 */
Junxiao Shi18739c42016-12-22 08:03:00 +000092 explicit
93 Strategy(Forwarder& forwarder);
Junxiao Shidbe71732014-02-21 22:23:28 -070094
Junxiao Shid3c792f2014-01-30 00:46:13 -070095 virtual
96 ~Strategy();
Junxiao Shidbe71732014-02-21 22:23:28 -070097
Junxiao Shi037f4ab2016-12-13 04:27:06 +000098#ifdef DOXYGEN
Eric Newberryc68b2e82020-04-16 12:40:30 -070099 /** \return Strategy program name
Junxiao Shi18739c42016-12-22 08:03:00 +0000100 *
101 * The strategy name is defined by the strategy program.
102 * It must end with a version component.
Junxiao Shi037f4ab2016-12-13 04:27:06 +0000103 */
104 static const Name&
105 getStrategyName();
106#endif
107
Eric Newberryc68b2e82020-04-16 12:40:30 -0700108 /** \return Strategy instance name
Junxiao Shi18739c42016-12-22 08:03:00 +0000109 *
110 * The instance name is assigned during instantiation.
111 * It contains a version component, and may have extra parameter components.
Junxiao Shib9420cf2016-08-13 04:38:52 +0000112 */
Junxiao Shibb5105f2014-03-03 12:06:45 -0700113 const Name&
Junxiao Shi18739c42016-12-22 08:03:00 +0000114 getInstanceName() const
Junxiao Shib9420cf2016-08-13 04:38:52 +0000115 {
116 return m_name;
117 }
Junxiao Shibb5105f2014-03-03 12:06:45 -0700118
Junxiao Shi679e9272014-02-15 20:10:21 -0700119public: // triggers
Davide Pesavento0498ce82021-06-14 02:02:21 -0400120 /**
121 * \brief Trigger after an Interest is received.
Junxiao Shi679e9272014-02-15 20:10:21 -0700122 *
Davide Pesavento0498ce82021-06-14 02:02:21 -0400123 * The Interest:
Eric Newberryc68b2e82020-04-16 12:40:30 -0700124 * - has not exceeded HopLimit
Junxiao Shi679e9272014-02-15 20:10:21 -0700125 * - does not violate Scope
126 * - is not looped
127 * - cannot be satisfied by ContentStore
128 * - is under a namespace managed by this strategy
129 *
Davide Pesavento0498ce82021-06-14 02:02:21 -0400130 * The PIT entry is set to expire after InterestLifetime has elapsed at each downstream.
Teng Liang7003e0b2018-03-03 16:03:30 -0700131 *
Davide Pesavento0498ce82021-06-14 02:02:21 -0400132 * The strategy should decide whether and where to forward this Interest.
Junxiao Shi679e9272014-02-15 20:10:21 -0700133 * - If the strategy decides to forward this Interest,
Davide Pesavento0498ce82021-06-14 02:02:21 -0400134 * invoke sendInterest() for each upstream, either now or shortly after via a scheduler event,
135 * but before the PIT entry expires.
136 * Optionally, the strategy can invoke setExpiryTimer() to adjust how long it would wait for a response.
137 * - If the strategy has already forwarded this Interest previously and decides to continue
138 * waiting, do nothing.
139 * Optionally, the strategy can invoke setExpiryTimer() to adjust how long it would wait for a response.
Teng Liang7003e0b2018-03-03 16:03:30 -0700140 * - If the strategy concludes that this Interest cannot be satisfied,
Davide Pesavento0498ce82021-06-14 02:02:21 -0400141 * invoke rejectPendingInterest() to erase the PIT entry.
Junxiao Shi82e7f582014-09-07 15:15:40 -0700142 *
Davide Pesavento0498ce82021-06-14 02:02:21 -0400143 * \warning The strategy must not retain a copy of the \p pitEntry shared_ptr after this function
144 * returns, otherwise undefined behavior may occur. However, the strategy is allowed to
145 * construct and keep a weak_ptr to \p pitEntry.
Junxiao Shi679e9272014-02-15 20:10:21 -0700146 */
Junxiao Shid3c792f2014-01-30 00:46:13 -0700147 virtual void
Davide Pesavento0498ce82021-06-14 02:02:21 -0400148 afterReceiveInterest(const Interest& interest, const FaceEndpoint& ingress,
Junxiao Shi15e98b02016-08-12 11:21:44 +0000149 const shared_ptr<pit::Entry>& pitEntry) = 0;
Junxiao Shidbe71732014-02-21 22:23:28 -0700150
Davide Pesavento0498ce82021-06-14 02:02:21 -0400151 /**
152 * \brief Trigger after a matching Data is found in the Content Store.
Junxiao Shi22be22c2014-02-16 22:53:48 -0700153 *
Davide Pesavento0498ce82021-06-14 02:02:21 -0400154 * In the base class, this method sends \p data to \p ingress.
Teng Liang7003e0b2018-03-03 16:03:30 -0700155 *
Davide Pesavento0498ce82021-06-14 02:02:21 -0400156 * \warning The strategy must not retain a copy of the \p pitEntry shared_ptr after this function
157 * returns, otherwise undefined behavior may occur. However, the strategy is allowed to
158 * construct and keep a weak_ptr to \p pitEntry.
Junxiao Shi22be22c2014-02-16 22:53:48 -0700159 */
160 virtual void
Davide Pesavento0498ce82021-06-14 02:02:21 -0400161 afterContentStoreHit(const Data& data, const FaceEndpoint& ingress,
162 const shared_ptr<pit::Entry>& pitEntry);
Junxiao Shidbe71732014-02-21 22:23:28 -0700163
Davide Pesavento0498ce82021-06-14 02:02:21 -0400164 /**
165 * \brief Trigger before a PIT entry is satisfied.
Teng Liang85a36632018-03-21 05:59:34 -0700166 *
Davide Pesavento0498ce82021-06-14 02:02:21 -0400167 * This trigger is invoked when an incoming Data satisfies more than one PIT entry.
168 * The strategy can collect measurements information, but cannot manipulate Data forwarding.
169 * When an incoming Data satisfies only one PIT entry, afterReceiveData() is invoked instead
170 * and given full control over Data forwarding. If a strategy does not override afterReceiveData(),
171 * the default implementation invokes beforeSatisfyInterest().
172 *
173 * Normally, PIT entries are erased after receiving the first matching Data.
174 * If the strategy wishes to collect responses from additional upstream nodes,
175 * it should invoke setExpiryTimer() within this function to prolong the PIT entry lifetime.
176 * If a Data arrives from another upstream during the extended PIT entry lifetime, this trigger
177 * will be invoked again. At that time, the strategy must invoke setExpiryTimer() again to
178 * continue collecting more responses.
179 *
180 * In the base class, this method does nothing.
181 *
182 * \warning The strategy must not retain a copy of the \p pitEntry shared_ptr after this function
183 * returns, otherwise undefined behavior may occur. However, the strategy is allowed to
184 * construct and keep a weak_ptr to \p pitEntry.
Teng Liang85a36632018-03-21 05:59:34 -0700185 */
186 virtual void
Davide Pesavento0498ce82021-06-14 02:02:21 -0400187 beforeSatisfyInterest(const Data& data, const FaceEndpoint& ingress,
188 const shared_ptr<pit::Entry>& pitEntry);
Teng Liang85a36632018-03-21 05:59:34 -0700189
Davide Pesavento0498ce82021-06-14 02:02:21 -0400190 /**
191 * \brief Trigger after Data is received.
Teng Liang43bb2312018-03-26 04:16:42 -0700192 *
Davide Pesavento0498ce82021-06-14 02:02:21 -0400193 * This trigger is invoked when an incoming Data satisfies exactly one PIT entry,
194 * and gives the strategy full control over Data forwarding.
Teng Liang43bb2312018-03-26 04:16:42 -0700195 *
Davide Pesavento0498ce82021-06-14 02:02:21 -0400196 * When this trigger is invoked:
Teng Liang43bb2312018-03-26 04:16:42 -0700197 * - The Data has been verified to satisfy the PIT entry.
198 * - The PIT entry expiry timer is set to now
199 *
Davide Pesavento0498ce82021-06-14 02:02:21 -0400200 * Inside this function:
201 * - A strategy should return Data to downstream nodes via sendData() or sendDataToAll().
Teng Liang43bb2312018-03-26 04:16:42 -0700202 * - A strategy can modify the Data as long as it still satisfies the PIT entry, such as
203 * adding or removing congestion marks.
Davide Pesavento0498ce82021-06-14 02:02:21 -0400204 * - A strategy can delay Data forwarding by prolonging the PIT entry lifetime via setExpiryTimer(),
205 * and later forward the Data before the PIT entry is erased.
Teng Liang43bb2312018-03-26 04:16:42 -0700206 * - A strategy can collect measurements about the upstream.
207 * - A strategy can collect responses from additional upstream nodes by prolonging the PIT entry
Davide Pesavento0498ce82021-06-14 02:02:21 -0400208 * lifetime via setExpiryTimer() every time a Data is received. Note that only one Data should
Teng Liang43bb2312018-03-26 04:16:42 -0700209 * be returned to each downstream node.
210 *
Davide Pesavento0498ce82021-06-14 02:02:21 -0400211 * In the base class, this method invokes beforeSatisfyInterest() and then returns the Data
212 * to all downstream faces via sendDataToAll().
213 *
214 * \warning The strategy must not retain a copy of the \p pitEntry shared_ptr after this function
215 * returns, otherwise undefined behavior may occur. However, the strategy is allowed to
216 * construct and keep a weak_ptr to \p pitEntry.
Teng Liang43bb2312018-03-26 04:16:42 -0700217 */
218 virtual void
Davide Pesavento0498ce82021-06-14 02:02:21 -0400219 afterReceiveData(const Data& data, const FaceEndpoint& ingress,
Junxiao Shi15e98b02016-08-12 11:21:44 +0000220 const shared_ptr<pit::Entry>& pitEntry);
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700221
Davide Pesavento0498ce82021-06-14 02:02:21 -0400222 /**
223 * \brief Trigger after a Nack is received.
Eric Newberry41aba102017-11-01 16:42:13 -0700224 *
Davide Pesavento0498ce82021-06-14 02:02:21 -0400225 * This trigger is invoked when an incoming Nack is received in response to
226 * an forwarded Interest.
227 * The Nack has been confirmed to be a response to the last Interest forwarded
228 * to that upstream, i.e. the PIT out-record exists and has a matching Nonce.
229 * The NackHeader has been recorded in the PIT out-record.
230 *
231 * If the PIT entry is not yet satisfied, its expiry timer remains unchanged.
232 * Otherwise, the PIT entry will normally expire immediately after this function returns.
233 *
234 * If the strategy wishes to collect responses from additional upstream nodes,
235 * it should invoke setExpiryTimer() within this function to prolong the PIT entry lifetime.
236 * If a Nack arrives from another upstream during the extended PIT entry lifetime, this trigger
237 * will be invoked again. At that time, the strategy must invoke setExpiryTimer() again to
238 * continue collecting more responses.
239 *
240 * In the base class, this method does nothing.
241 *
242 * \warning The strategy must not retain a copy of the \p pitEntry shared_ptr after this function
243 * returns, otherwise undefined behavior may occur. However, the strategy is allowed to
244 * construct and keep a weak_ptr to \p pitEntry.
Eric Newberry41aba102017-11-01 16:42:13 -0700245 */
246 virtual void
Davide Pesavento0498ce82021-06-14 02:02:21 -0400247 afterReceiveNack(const lp::Nack& nack, const FaceEndpoint& ingress,
248 const shared_ptr<pit::Entry>& pitEntry);
Eric Newberry41aba102017-11-01 16:42:13 -0700249
Davide Pesavento0498ce82021-06-14 02:02:21 -0400250 /**
251 * \brief Trigger after an Interest is dropped (e.g., for exceeding allowed retransmissions).
Ju Pan2feb4592019-09-16 20:56:38 +0000252 *
Davide Pesavento0498ce82021-06-14 02:02:21 -0400253 * In the base class, this method does nothing.
254 */
255 virtual void
256 onDroppedInterest(const Interest& interest, Face& egress);
257
258 /**
259 * \brief Trigger after a new nexthop is added.
260 *
261 * The strategy should decide whether to send the buffered Interests to the new nexthop.
262 *
263 * In the base class, this method does nothing.
Ju Pan2feb4592019-09-16 20:56:38 +0000264 */
265 virtual void
266 afterNewNextHop(const fib::NextHop& nextHop, const shared_ptr<pit::Entry>& pitEntry);
267
Junxiao Shid3c792f2014-01-30 00:46:13 -0700268protected: // actions
Davide Pesavento0498ce82021-06-14 02:02:21 -0400269 /**
270 * \brief Send an Interest packet.
271 * \param interest the Interest packet
272 * \param egress face through which to send out the Interest
273 * \param pitEntry the PIT entry
274 * \return A pointer to the out-record created or nullptr if the Interest was dropped
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700275 */
Davide Pesavento264af772021-02-09 21:48:24 -0500276 NFD_VIRTUAL_WITH_TESTS pit::OutRecord*
Davide Pesavento0498ce82021-06-14 02:02:21 -0400277 sendInterest(const Interest& interest, Face& egress, const shared_ptr<pit::Entry>& pitEntry);
Junxiao Shidbe71732014-02-21 22:23:28 -0700278
Davide Pesavento0498ce82021-06-14 02:02:21 -0400279 /**
280 * \brief Send a Data packet.
281 * \param data the Data packet
282 * \param egress face through which to send out the Data
283 * \param pitEntry the PIT entry
284 * \return Whether the Data was sent (true) or dropped (false)
Teng Liang85a36632018-03-21 05:59:34 -0700285 */
Davide Pesavento264af772021-02-09 21:48:24 -0500286 NFD_VIRTUAL_WITH_TESTS bool
Davide Pesavento0498ce82021-06-14 02:02:21 -0400287 sendData(const Data& data, Face& egress, const shared_ptr<pit::Entry>& pitEntry);
Teng Liang85a36632018-03-21 05:59:34 -0700288
Davide Pesavento0498ce82021-06-14 02:02:21 -0400289 /**
290 * \brief Send a Data packet to all matched and qualified faces.
Teng Liang43bb2312018-03-26 04:16:42 -0700291 *
Davide Pesavento0498ce82021-06-14 02:02:21 -0400292 * A matched face qualifies if it is ad-hoc OR it is NOT \p inFace.
Teng Liang43bb2312018-03-26 04:16:42 -0700293 *
Davide Pesavento0498ce82021-06-14 02:02:21 -0400294 * \param data the Data packet
295 * \param pitEntry the PIT entry
296 * \param inFace face on which the Data arrived
Teng Liang43bb2312018-03-26 04:16:42 -0700297 */
Davide Pesavento264af772021-02-09 21:48:24 -0500298 NFD_VIRTUAL_WITH_TESTS void
Davide Pesavento0498ce82021-06-14 02:02:21 -0400299 sendDataToAll(const Data& data, const shared_ptr<pit::Entry>& pitEntry, const Face& inFace);
Teng Liang85a36632018-03-21 05:59:34 -0700300
Davide Pesavento0498ce82021-06-14 02:02:21 -0400301 /**
302 * \brief Schedule the PIT entry for immediate deletion.
Junxiao Shi679e9272014-02-15 20:10:21 -0700303 *
Davide Pesavento0498ce82021-06-14 02:02:21 -0400304 * This helper function sets the PIT entry expiry time to zero.
305 * The strategy should invoke this function when it concludes that the Interest cannot
306 * be forwarded and it does not want to wait for responses from existing upstream nodes.
Junxiao Shid3c792f2014-01-30 00:46:13 -0700307 */
Davide Pesavento264af772021-02-09 21:48:24 -0500308 NFD_VIRTUAL_WITH_TESTS void
Junxiao Shib9420cf2016-08-13 04:38:52 +0000309 rejectPendingInterest(const shared_ptr<pit::Entry>& pitEntry)
310 {
Teng Liang7003e0b2018-03-03 16:03:30 -0700311 this->setExpiryTimer(pitEntry, 0_ms);
Junxiao Shib9420cf2016-08-13 04:38:52 +0000312 }
Junxiao Shidbe71732014-02-21 22:23:28 -0700313
Davide Pesavento0498ce82021-06-14 02:02:21 -0400314 /**
315 * \brief Send a Nack packet.
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700316 *
Davide Pesavento0498ce82021-06-14 02:02:21 -0400317 * The egress face must have a PIT in-record, otherwise this method has no effect.
Teng Liangebc20f62020-06-23 16:55:20 -0700318 *
Davide Pesavento0498ce82021-06-14 02:02:21 -0400319 * \param header the Nack header
320 * \param egress face through which to send out the Nack
321 * \param pitEntry the PIT entry
322 * \return Whether the Nack was sent (true) or dropped (false)
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700323 */
Davide Pesavento264af772021-02-09 21:48:24 -0500324 NFD_VIRTUAL_WITH_TESTS bool
Davide Pesavento0498ce82021-06-14 02:02:21 -0400325 sendNack(const lp::NackHeader& header, Face& egress, const shared_ptr<pit::Entry>& pitEntry)
Junxiao Shib9420cf2016-08-13 04:38:52 +0000326 {
Davide Pesavento0498ce82021-06-14 02:02:21 -0400327 return m_forwarder.onOutgoingNack(header, egress, pitEntry);
Junxiao Shib9420cf2016-08-13 04:38:52 +0000328 }
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700329
Davide Pesavento0498ce82021-06-14 02:02:21 -0400330 /**
331 * \brief Send Nack to every face that has an in-record, except those in \p exceptFaces
332 * \param header the Nack header
333 * \param pitEntry the PIT entry
334 * \param exceptFaces list of faces that should be excluded from sending Nacks
335 * \note This is not an action, but a helper that invokes the sendNack() action.
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700336 */
337 void
Davide Pesavento0498ce82021-06-14 02:02:21 -0400338 sendNacks(const lp::NackHeader& header, const shared_ptr<pit::Entry>& pitEntry,
Teng Liangebc20f62020-06-23 16:55:20 -0700339 std::initializer_list<const Face*> exceptFaces = {});
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700340
Davide Pesavento0498ce82021-06-14 02:02:21 -0400341 /**
342 * \brief Schedule the PIT entry to be erased after \p duration.
Teng Liang7003e0b2018-03-03 16:03:30 -0700343 */
344 void
345 setExpiryTimer(const shared_ptr<pit::Entry>& pitEntry, time::milliseconds duration)
346 {
347 m_forwarder.setExpiryTimer(pitEntry, duration);
348 }
349
Junxiao Shidbe71732014-02-21 22:23:28 -0700350protected: // accessors
Davide Pesavento0498ce82021-06-14 02:02:21 -0400351 /**
352 * \brief Performs a FIB lookup, considering Link object if present.
Junxiao Shicf0f3ce2016-09-02 13:01:59 +0000353 */
Junxiao Shi8d843142016-07-11 22:42:42 +0000354 const fib::Entry&
Junxiao Shicf0f3ce2016-09-02 13:01:59 +0000355 lookupFib(const pit::Entry& pitEntry) const;
Junxiao Shi8d843142016-07-11 22:42:42 +0000356
Junxiao Shidbe71732014-02-21 22:23:28 -0700357 MeasurementsAccessor&
Junxiao Shib9420cf2016-08-13 04:38:52 +0000358 getMeasurements()
359 {
360 return m_measurements;
361 }
Junxiao Shidbe71732014-02-21 22:23:28 -0700362
Junxiao Shi5b43f9a2016-07-19 13:15:56 +0000363 Face*
Junxiao Shib9420cf2016-08-13 04:38:52 +0000364 getFace(FaceId id) const
365 {
Davide Pesaventoa4abfb02019-10-06 16:02:56 -0400366 return getFaceTable().get(id);
Junxiao Shib9420cf2016-08-13 04:38:52 +0000367 }
Junxiao Shi2d9bdc82014-03-02 20:55:42 -0700368
Junxiao Shi49e11e72014-12-14 19:46:05 -0700369 const FaceTable&
Junxiao Shib9420cf2016-08-13 04:38:52 +0000370 getFaceTable() const
371 {
Davide Pesaventoa4abfb02019-10-06 16:02:56 -0400372 return m_forwarder.m_faceTable;
Junxiao Shib9420cf2016-08-13 04:38:52 +0000373 }
Junxiao Shi49e11e72014-12-14 19:46:05 -0700374
Junxiao Shi18739c42016-12-22 08:03:00 +0000375protected: // instance name
376 struct ParsedInstanceName
377 {
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400378 Name strategyName; ///< Strategy name without parameters
Davide Pesaventob7bfcb92022-05-22 23:55:23 -0400379 std::optional<uint64_t> version; ///< The strategy version number, if present
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400380 PartialName parameters; ///< Parameter components, may be empty
Junxiao Shi18739c42016-12-22 08:03:00 +0000381 };
382
Eric Newberryc68b2e82020-04-16 12:40:30 -0700383 /** \brief Parse a strategy instance name
Junxiao Shi18739c42016-12-22 08:03:00 +0000384 * \param input strategy instance name, may contain version and parameters
385 * \throw std::invalid_argument input format is unacceptable
386 */
387 static ParsedInstanceName
388 parseInstanceName(const Name& input);
389
Eric Newberryc68b2e82020-04-16 12:40:30 -0700390 /** \brief Construct a strategy instance name
Junxiao Shi18739c42016-12-22 08:03:00 +0000391 * \param input strategy instance name, may contain version and parameters
392 * \param strategyName strategy name with version but without parameters;
393 * typically this should be \p getStrategyName()
394 *
395 * If \p input contains a version component, return \p input unchanged.
396 * Otherwise, return \p input plus the version component taken from \p strategyName.
397 * This allows a strategy instance to be constructed with an unversioned name,
398 * but its final instance name should contain the version.
399 */
400 static Name
401 makeInstanceName(const Name& input, const Name& strategyName);
402
Eric Newberryc68b2e82020-04-16 12:40:30 -0700403 /** \brief Set strategy instance name
Junxiao Shi18739c42016-12-22 08:03:00 +0000404 * \note This must be called by strategy subclass constructor.
405 */
406 void
407 setInstanceName(const Name& name)
408 {
409 m_name = name;
410 }
Junxiao Shi49e11e72014-12-14 19:46:05 -0700411
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400412NFD_PUBLIC_WITH_TESTS_ELSE_PROTECTED:
413 /**
414 * \brief Parse strategy parameters encoded in a strategy instance name
415 * \param params encoded parameters, typically obtained from a call to parseInstanceName()
416 * \throw std::invalid_argument the encoding format is invalid or unsupported by this implementation
417 */
418 static StrategyParameters
419 parseParameters(const PartialName& params);
420
Junxiao Shic34d1672016-12-09 15:57:59 +0000421private: // registry
Davide Pesavento0498ce82021-06-14 02:02:21 -0400422 using CreateFunc = std::function<unique_ptr<Strategy>(Forwarder&, const Name& /*strategyName*/)>;
423 using Registry = std::map<Name, CreateFunc>; // indexed by strategy name
Junxiao Shic34d1672016-12-09 15:57:59 +0000424
425 static Registry&
426 getRegistry();
427
428 static Registry::const_iterator
Junxiao Shi18739c42016-12-22 08:03:00 +0000429 find(const Name& instanceName);
430
431protected: // accessors
Davide Pesaventoa4abfb02019-10-06 16:02:56 -0400432 signal::Signal<FaceTable, Face>& afterAddFace;
433 signal::Signal<FaceTable, Face>& beforeRemoveFace;
Junxiao Shic34d1672016-12-09 15:57:59 +0000434
435private: // instance fields
Junxiao Shibb5105f2014-03-03 12:06:45 -0700436 Name m_name;
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700437 Forwarder& m_forwarder;
Junxiao Shidbe71732014-02-21 22:23:28 -0700438 MeasurementsAccessor m_measurements;
Junxiao Shid3c792f2014-01-30 00:46:13 -0700439};
440
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400441class StrategyParameters : public std::map<std::string, std::string>
442{
443public:
444 // Note: only arithmetic types are supported by getOrDefault() for now
445
446 template<typename T>
Davide Pesaventob7bfcb92022-05-22 23:55:23 -0400447 std::enable_if_t<std::is_signed_v<T>, T>
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400448 getOrDefault(const key_type& key, const T& defaultVal) const
449 {
450 auto it = find(key);
451 if (it == end()) {
452 return defaultVal;
453 }
454
455 T val{};
456 if (!boost::conversion::try_lexical_convert(it->second, val)) {
457 NDN_THROW(std::invalid_argument(key + " value is malformed"));
458 }
459 return val;
460 }
461
462 template<typename T>
Davide Pesaventob7bfcb92022-05-22 23:55:23 -0400463 std::enable_if_t<std::is_unsigned_v<T>, T>
Ashlesh Gawande1ef93d02022-04-08 00:25:06 -0400464 getOrDefault(const key_type& key, const T& defaultVal) const
465 {
466 auto it = find(key);
467 if (it == end()) {
468 return defaultVal;
469 }
470
471 if (it->second.find('-') != std::string::npos) {
472 NDN_THROW(std::invalid_argument(key + " cannot be negative"));
473 }
474
475 T val{};
476 if (!boost::conversion::try_lexical_convert(it->second, val)) {
477 NDN_THROW(std::invalid_argument(key + " value is malformed"));
478 }
479 return val;
480 }
481};
482
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700483} // namespace fw
Junxiao Shid3c792f2014-01-30 00:46:13 -0700484} // namespace nfd
485
Eric Newberryc68b2e82020-04-16 12:40:30 -0700486/** \brief Registers a strategy
Junxiao Shic34d1672016-12-09 15:57:59 +0000487 *
488 * This macro should appear once in .cpp of each strategy.
489 */
490#define NFD_REGISTER_STRATEGY(S) \
491static class NfdAuto ## S ## StrategyRegistrationClass \
492{ \
493public: \
494 NfdAuto ## S ## StrategyRegistrationClass() \
495 { \
496 ::nfd::fw::Strategy::registerType<S>(); \
497 } \
498} g_nfdAuto ## S ## StrategyRegistrationVariable
499
Alexander Afanasyev613e2a92014-04-15 13:36:58 -0700500#endif // NFD_DAEMON_FW_STRATEGY_HPP