blob: 2f20b5c66a77449daa1d93d4d462d1ba78bc06d1 [file] [log] [blame]
Alexander Afanasyev33b72772014-01-26 23:22:58 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -07003 * Copyright (c) 2014 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 *
10 * This file is part of NFD (Named Data Networking Forwarding Daemon).
11 * See AUTHORS.md for complete list of NFD authors and contributors.
12 *
13 * NFD is free software: you can redistribute it and/or modify it under the terms
14 * of the GNU General Public License as published by the Free Software Foundation,
15 * either version 3 of the License, or (at your option) any later version.
16 *
17 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
18 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
19 * PURPOSE. See the GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along with
22 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
23 **/
Alexander Afanasyev33b72772014-01-26 23:22:58 -080024
25#include "forwarder.hpp"
Junxiao Shid938a6b2014-05-11 23:40:29 -070026#include <ndn-cxx/util/random.hpp>
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060027#include "core/logger.hpp"
Junxiao Shid938a6b2014-05-11 23:40:29 -070028#include "available-strategies.hpp"
Alexander Afanasyev33b72772014-01-26 23:22:58 -080029
Alexander Afanasyev18bbf812014-01-29 01:40:23 -080030namespace nfd {
Alexander Afanasyev33b72772014-01-26 23:22:58 -080031
Junxiao Shi8c8d2182014-01-30 22:33:00 -070032NFD_LOG_INIT("Forwarder");
33
Junxiao Shif3c07812014-03-11 21:48:49 -070034using fw::Strategy;
35
Junxiao Shif3c07812014-03-11 21:48:49 -070036const Name Forwarder::LOCALHOST_NAME("ndn:/localhost");
Junxiao Shi88884492014-02-15 15:57:43 -070037
Junxiao Shic041ca32014-02-25 20:01:15 -070038Forwarder::Forwarder()
Junxiao Shia4f2be82014-03-02 22:56:41 -070039 : m_faceTable(*this)
HangZhangad4afd12014-03-01 11:03:08 +080040 , m_fib(m_nameTree)
Haowei Yuan78c84d12014-02-27 15:35:13 -060041 , m_pit(m_nameTree)
HangZhangc85a23c2014-03-01 15:55:55 +080042 , m_measurements(m_nameTree)
Junxiao Shif3c07812014-03-11 21:48:49 -070043 , m_strategyChoice(m_nameTree, fw::makeDefaultStrategy(*this))
Alexander Afanasyev33b72772014-01-26 23:22:58 -080044{
Junxiao Shif3c07812014-03-11 21:48:49 -070045 fw::installStrategies(*this);
Alexander Afanasyev33b72772014-01-26 23:22:58 -080046}
47
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060048Forwarder::~Forwarder()
49{
50
51}
52
Alexander Afanasyev33b72772014-01-26 23:22:58 -080053void
Junxiao Shid3c792f2014-01-30 00:46:13 -070054Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
55{
56 // receive Interest
Junxiao Shif3c07812014-03-11 21:48:49 -070057 NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() <<
58 " interest=" << interest.getName());
Junxiao Shi06887ac2014-02-13 20:15:42 -070059 const_cast<Interest&>(interest).setIncomingFaceId(inFace.getId());
Junxiao Shi6e694322014-04-03 10:27:13 -070060 m_counters.getNInInterests() ++;
Junxiao Shic041ca32014-02-25 20:01:15 -070061
Junxiao Shi88884492014-02-15 15:57:43 -070062 // /localhost scope control
Junxiao Shif3c07812014-03-11 21:48:49 -070063 bool isViolatingLocalhost = !inFace.isLocal() &&
64 LOCALHOST_NAME.isPrefixOf(interest.getName());
65 if (isViolatingLocalhost) {
66 NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() <<
67 " interest=" << interest.getName() << " violates /localhost");
68 // (drop)
Junxiao Shi88884492014-02-15 15:57:43 -070069 return;
70 }
Junxiao Shic041ca32014-02-25 20:01:15 -070071
Junxiao Shid3c792f2014-01-30 00:46:13 -070072 // PIT insert
Junxiao Shi40631842014-03-01 13:52:37 -070073 shared_ptr<pit::Entry> pitEntry = m_pit.insert(interest).first;
Junxiao Shic041ca32014-02-25 20:01:15 -070074
Junxiao Shid3c792f2014-01-30 00:46:13 -070075 // detect loop and record Nonce
76 bool isLoop = ! pitEntry->addNonce(interest.getNonce());
77 if (isLoop) {
78 // goto Interest loop pipeline
79 this->onInterestLoop(inFace, interest, pitEntry);
80 return;
81 }
Junxiao Shic041ca32014-02-25 20:01:15 -070082
Junxiao Shid3c792f2014-01-30 00:46:13 -070083 // cancel unsatisfy & straggler timer
84 this->cancelUnsatisfyAndStragglerTimer(pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -070085
Junxiao Shif3c07812014-03-11 21:48:49 -070086 // is pending?
Junxiao Shid3c792f2014-01-30 00:46:13 -070087 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
Junxiao Shie17349a2014-03-25 00:55:38 -070088 bool isPending = inRecords.begin() != inRecords.end();
Junxiao Shid3c792f2014-01-30 00:46:13 -070089 if (!isPending) {
90 // CS lookup
91 const Data* csMatch = m_cs.find(interest);
92 if (csMatch != 0) {
93 // XXX should we lookup PIT for other Interests that also match csMatch?
94
95 // goto outgoing Data pipeline
96 this->onOutgoingData(*csMatch, inFace);
97 return;
98 }
99 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700100
Junxiao Shid3c792f2014-01-30 00:46:13 -0700101 // insert InRecord
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700102 pitEntry->insertOrUpdateInRecord(inFace.shared_from_this(), interest);
Junxiao Shic041ca32014-02-25 20:01:15 -0700103
Junxiao Shid3c792f2014-01-30 00:46:13 -0700104 // FIB lookup
Junxiao Shi40631842014-03-01 13:52:37 -0700105 shared_ptr<fib::Entry> fibEntry = m_fib.findLongestPrefixMatch(*pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -0700106
Junxiao Shid3c792f2014-01-30 00:46:13 -0700107 // dispatch to strategy
Junxiao Shif3c07812014-03-11 21:48:49 -0700108 this->dispatchToStrategy(pitEntry, bind(&Strategy::afterReceiveInterest, _1,
Alexander Afanasyevf6980282014-05-13 18:28:40 -0700109 cref(inFace), cref(interest), fibEntry, pitEntry));
Junxiao Shid3c792f2014-01-30 00:46:13 -0700110}
111
112void
113Forwarder::onInterestLoop(Face& inFace, const Interest& interest,
114 shared_ptr<pit::Entry> pitEntry)
115{
Junxiao Shif3c07812014-03-11 21:48:49 -0700116 NFD_LOG_DEBUG("onInterestLoop face=" << inFace.getId() <<
117 " interest=" << interest.getName());
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700118
Junxiao Shif3c07812014-03-11 21:48:49 -0700119 // (drop)
120}
121
122/** \brief compare two InRecords for picking outgoing Interest
123 * \return true if b is preferred over a
124 *
125 * This function should be passed to std::max_element over InRecordCollection.
126 * The outgoing Interest picked is the last incoming Interest
127 * that does not come from outFace.
128 * If all InRecords come from outFace, it's fine to pick that. This happens when
129 * there's only one InRecord that comes from outFace. The legit use is for
130 * vehicular network; otherwise, strategy shouldn't send to the sole inFace.
131 */
132static inline bool
133compare_pickInterest(const pit::InRecord& a, const pit::InRecord& b, const Face* outFace)
134{
135 bool isOutFaceA = a.getFace().get() == outFace;
136 bool isOutFaceB = b.getFace().get() == outFace;
137
138 if (!isOutFaceA && isOutFaceB) {
139 return false;
140 }
141 if (isOutFaceA && !isOutFaceB) {
142 return true;
143 }
144
145 return a.getLastRenewed() > b.getLastRenewed();
Junxiao Shid3c792f2014-01-30 00:46:13 -0700146}
147
148void
Junxiao Shid938a6b2014-05-11 23:40:29 -0700149Forwarder::onOutgoingInterest(shared_ptr<pit::Entry> pitEntry, Face& outFace,
150 bool wantNewNonce)
Junxiao Shid3c792f2014-01-30 00:46:13 -0700151{
Junxiao Shif3c07812014-03-11 21:48:49 -0700152 NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() <<
153 " interest=" << pitEntry->getName());
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700154
Junxiao Shi57f0f312014-03-16 11:52:20 -0700155 // scope control
156 if (pitEntry->violatesScope(outFace)) {
Junxiao Shif3c07812014-03-11 21:48:49 -0700157 NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() <<
Junxiao Shi57f0f312014-03-16 11:52:20 -0700158 " interest=" << pitEntry->getName() << " violates scope");
Junxiao Shi11bd9c22014-03-13 20:44:13 -0700159 return;
160 }
161
Junxiao Shid3c792f2014-01-30 00:46:13 -0700162 // pick Interest
Junxiao Shif3c07812014-03-11 21:48:49 -0700163 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
164 pit::InRecordCollection::const_iterator pickedInRecord = std::max_element(
165 inRecords.begin(), inRecords.end(), bind(&compare_pickInterest, _1, _2, &outFace));
166 BOOST_ASSERT(pickedInRecord != inRecords.end());
Junxiao Shid938a6b2014-05-11 23:40:29 -0700167 shared_ptr<Interest> interest = const_pointer_cast<Interest>(
168 pickedInRecord->getInterest().shared_from_this());
169
170 if (wantNewNonce) {
171 interest = make_shared<Interest>(*interest);
172 interest->setNonce(ndn::random::generateWord32());
173 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700174
Junxiao Shid3c792f2014-01-30 00:46:13 -0700175 // insert OutRecord
Junxiao Shid938a6b2014-05-11 23:40:29 -0700176 pitEntry->insertOrUpdateOutRecord(outFace.shared_from_this(), *interest);
Junxiao Shic041ca32014-02-25 20:01:15 -0700177
Junxiao Shid3c792f2014-01-30 00:46:13 -0700178 // set PIT unsatisfy timer
179 this->setUnsatisfyTimer(pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -0700180
Junxiao Shid3c792f2014-01-30 00:46:13 -0700181 // send Interest
Junxiao Shid938a6b2014-05-11 23:40:29 -0700182 outFace.sendInterest(*interest);
Junxiao Shi6e694322014-04-03 10:27:13 -0700183 m_counters.getNOutInterests() ++;
Junxiao Shid3c792f2014-01-30 00:46:13 -0700184}
185
186void
Junxiao Shi09498f02014-02-26 19:41:08 -0700187Forwarder::onInterestReject(shared_ptr<pit::Entry> pitEntry)
Junxiao Shid3c792f2014-01-30 00:46:13 -0700188{
Junxiao Shid938a6b2014-05-11 23:40:29 -0700189 if (pitEntry->hasUnexpiredOutRecords()) {
190 NFD_LOG_ERROR("onInterestReject interest=" << pitEntry->getName() <<
191 " cannot reject forwarded Interest");
192 return;
193 }
Junxiao Shi09498f02014-02-26 19:41:08 -0700194 NFD_LOG_DEBUG("onInterestReject interest=" << pitEntry->getName());
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700195
Junxiao Shid3c792f2014-01-30 00:46:13 -0700196 // set PIT straggler timer
197 this->setStragglerTimer(pitEntry);
198}
199
200void
201Forwarder::onInterestUnsatisfied(shared_ptr<pit::Entry> pitEntry)
202{
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700203 NFD_LOG_DEBUG("onInterestUnsatisfied interest=" << pitEntry->getName());
204
Junxiao Shid3c792f2014-01-30 00:46:13 -0700205 // invoke PIT unsatisfied callback
Junxiao Shif3c07812014-03-11 21:48:49 -0700206 this->dispatchToStrategy(pitEntry, bind(&Strategy::beforeExpirePendingInterest, _1,
Alexander Afanasyevf6980282014-05-13 18:28:40 -0700207 pitEntry));
Junxiao Shic041ca32014-02-25 20:01:15 -0700208
Junxiao Shif3c07812014-03-11 21:48:49 -0700209 // PIT delete
Junxiao Shid938a6b2014-05-11 23:40:29 -0700210 this->cancelUnsatisfyAndStragglerTimer(pitEntry);
Haowei Yuan78c84d12014-02-27 15:35:13 -0600211 m_pit.erase(pitEntry);
Junxiao Shid3c792f2014-01-30 00:46:13 -0700212}
213
214void
215Forwarder::onIncomingData(Face& inFace, const Data& data)
216{
217 // receive Data
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700218 NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId() << " data=" << data.getName());
Junxiao Shi06887ac2014-02-13 20:15:42 -0700219 const_cast<Data&>(data).setIncomingFaceId(inFace.getId());
Junxiao Shi6e694322014-04-03 10:27:13 -0700220 m_counters.getNInDatas() ++;
Junxiao Shic041ca32014-02-25 20:01:15 -0700221
Junxiao Shi88884492014-02-15 15:57:43 -0700222 // /localhost scope control
Junxiao Shif3c07812014-03-11 21:48:49 -0700223 bool isViolatingLocalhost = !inFace.isLocal() &&
224 LOCALHOST_NAME.isPrefixOf(data.getName());
225 if (isViolatingLocalhost) {
226 NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId() <<
227 " data=" << data.getName() << " violates /localhost");
228 // (drop)
Junxiao Shi88884492014-02-15 15:57:43 -0700229 return;
230 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700231
Junxiao Shid3c792f2014-01-30 00:46:13 -0700232 // PIT match
233 shared_ptr<pit::DataMatchResult> pitMatches = m_pit.findAllDataMatches(data);
234 if (pitMatches->begin() == pitMatches->end()) {
235 // goto Data unsolicited pipeline
236 this->onDataUnsolicited(inFace, data);
237 return;
238 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700239
Junxiao Shid3c792f2014-01-30 00:46:13 -0700240 // CS insert
241 m_cs.insert(data);
Junxiao Shic041ca32014-02-25 20:01:15 -0700242
Junxiao Shid3c792f2014-01-30 00:46:13 -0700243 std::set<shared_ptr<Face> > pendingDownstreams;
244 // foreach PitEntry
245 for (pit::DataMatchResult::iterator it = pitMatches->begin();
246 it != pitMatches->end(); ++it) {
247 shared_ptr<pit::Entry> pitEntry = *it;
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700248 NFD_LOG_DEBUG("onIncomingData matching=" << pitEntry->getName());
Junxiao Shic041ca32014-02-25 20:01:15 -0700249
Junxiao Shid3c792f2014-01-30 00:46:13 -0700250 // cancel unsatisfy & straggler timer
251 this->cancelUnsatisfyAndStragglerTimer(pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -0700252
Junxiao Shid3c792f2014-01-30 00:46:13 -0700253 // remember pending downstreams
254 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
255 for (pit::InRecordCollection::const_iterator it = inRecords.begin();
256 it != inRecords.end(); ++it) {
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -0700257 if (it->getExpiry() > time::steady_clock::now()) {
Junxiao Shid3c792f2014-01-30 00:46:13 -0700258 pendingDownstreams.insert(it->getFace());
259 }
260 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700261
Junxiao Shid938a6b2014-05-11 23:40:29 -0700262 // invoke PIT satisfy callback
263 this->dispatchToStrategy(pitEntry, bind(&Strategy::beforeSatisfyPendingInterest, _1,
264 pitEntry, cref(inFace), cref(data)));
265
Junxiao Shid3c792f2014-01-30 00:46:13 -0700266 // mark PIT satisfied
267 pitEntry->deleteInRecords();
268 pitEntry->deleteOutRecord(inFace.shared_from_this());
Junxiao Shic041ca32014-02-25 20:01:15 -0700269
Junxiao Shid3c792f2014-01-30 00:46:13 -0700270 // set PIT straggler timer
271 this->setStragglerTimer(pitEntry);
Junxiao Shid3c792f2014-01-30 00:46:13 -0700272 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700273
Junxiao Shid3c792f2014-01-30 00:46:13 -0700274 // foreach pending downstream
275 for (std::set<shared_ptr<Face> >::iterator it = pendingDownstreams.begin();
276 it != pendingDownstreams.end(); ++it) {
277 // goto outgoing Data pipeline
278 this->onOutgoingData(data, **it);
279 }
280}
281
282void
283Forwarder::onDataUnsolicited(Face& inFace, const Data& data)
284{
285 // accept to cache?
Junxiao Shif3c07812014-03-11 21:48:49 -0700286 bool acceptToCache = inFace.isLocal();
Junxiao Shid3c792f2014-01-30 00:46:13 -0700287 if (acceptToCache) {
288 // CS insert
Junxiao Shif3c07812014-03-11 21:48:49 -0700289 m_cs.insert(data, true);
Junxiao Shid3c792f2014-01-30 00:46:13 -0700290 }
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700291
Junxiao Shif3c07812014-03-11 21:48:49 -0700292 NFD_LOG_DEBUG("onDataUnsolicited face=" << inFace.getId() <<
293 " data=" << data.getName() <<
294 (acceptToCache ? " cached" : " not cached"));
Junxiao Shid3c792f2014-01-30 00:46:13 -0700295}
296
297void
298Forwarder::onOutgoingData(const Data& data, Face& outFace)
299{
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700300 NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId() << " data=" << data.getName());
301
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700302 // /localhost scope control
Junxiao Shif3c07812014-03-11 21:48:49 -0700303 bool isViolatingLocalhost = !outFace.isLocal() &&
304 LOCALHOST_NAME.isPrefixOf(data.getName());
305 if (isViolatingLocalhost) {
306 NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId() <<
307 " data=" << data.getName() << " violates /localhost");
308 // (drop)
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700309 return;
310 }
311
Junxiao Shif3c07812014-03-11 21:48:49 -0700312 // TODO traffic manager
Junxiao Shic041ca32014-02-25 20:01:15 -0700313
Junxiao Shid3c792f2014-01-30 00:46:13 -0700314 // send Data
315 outFace.sendData(data);
Junxiao Shi6e694322014-04-03 10:27:13 -0700316 m_counters.getNOutDatas() ++;
Junxiao Shid3c792f2014-01-30 00:46:13 -0700317}
318
319static inline bool
320compare_InRecord_expiry(const pit::InRecord& a, const pit::InRecord& b)
321{
322 return a.getExpiry() < b.getExpiry();
323}
324
325void
326Forwarder::setUnsatisfyTimer(shared_ptr<pit::Entry> pitEntry)
327{
328 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
329 pit::InRecordCollection::const_iterator lastExpiring =
330 std::max_element(inRecords.begin(), inRecords.end(),
331 &compare_InRecord_expiry);
332
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -0700333 time::steady_clock::TimePoint lastExpiry = lastExpiring->getExpiry();
334 time::nanoseconds lastExpiryFromNow = lastExpiry - time::steady_clock::now();
Junxiao Shid3c792f2014-01-30 00:46:13 -0700335 if (lastExpiryFromNow <= time::seconds(0)) {
336 // TODO all InRecords are already expired; will this happen?
337 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700338
Junxiao Shi9f7455b2014-04-07 21:02:16 -0700339 scheduler::cancel(pitEntry->m_unsatisfyTimer);
Junxiao Shic041ca32014-02-25 20:01:15 -0700340 pitEntry->m_unsatisfyTimer = scheduler::schedule(lastExpiryFromNow,
Junxiao Shid3c792f2014-01-30 00:46:13 -0700341 bind(&Forwarder::onInterestUnsatisfied, this, pitEntry));
342}
343
344void
345Forwarder::setStragglerTimer(shared_ptr<pit::Entry> pitEntry)
346{
Junxiao Shi57f0f312014-03-16 11:52:20 -0700347 if (pitEntry->hasUnexpiredOutRecords()) {
348 NFD_LOG_DEBUG("setStragglerTimer " << pitEntry->getName() <<
349 " cannot set StragglerTimer when an OutRecord is pending");
350 return;
351 }
352
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -0700353 time::nanoseconds stragglerTime = time::milliseconds(100);
Junxiao Shic041ca32014-02-25 20:01:15 -0700354
Junxiao Shi9f7455b2014-04-07 21:02:16 -0700355 scheduler::cancel(pitEntry->m_stragglerTimer);
Junxiao Shic041ca32014-02-25 20:01:15 -0700356 pitEntry->m_stragglerTimer = scheduler::schedule(stragglerTime,
Haowei Yuan78c84d12014-02-27 15:35:13 -0600357 bind(&Pit::erase, &m_pit, pitEntry));
Junxiao Shid3c792f2014-01-30 00:46:13 -0700358}
359
360void
361Forwarder::cancelUnsatisfyAndStragglerTimer(shared_ptr<pit::Entry> pitEntry)
362{
Junxiao Shic041ca32014-02-25 20:01:15 -0700363 scheduler::cancel(pitEntry->m_unsatisfyTimer);
364 scheduler::cancel(pitEntry->m_stragglerTimer);
Junxiao Shid3c792f2014-01-30 00:46:13 -0700365}
366
Alexander Afanasyev18bbf812014-01-29 01:40:23 -0800367} // namespace nfd