blob: 3a8a91fcfe71557b3e53994cbad9a33206ac5691 [file] [log] [blame]
Alexander Afanasyev33b72772014-01-26 23:22:58 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (C) 2014 Named Data Networking Project
4 * See COPYING for copyright and distribution information.
5 */
6
7#include "forwarder.hpp"
Junxiao Shif3c07812014-03-11 21:48:49 -07008#include "available-strategies.hpp"
Alexander Afanasyev33b72772014-01-26 23:22:58 -08009
Alexander Afanasyev18bbf812014-01-29 01:40:23 -080010namespace nfd {
Alexander Afanasyev33b72772014-01-26 23:22:58 -080011
Junxiao Shi8c8d2182014-01-30 22:33:00 -070012NFD_LOG_INIT("Forwarder");
13
Junxiao Shif3c07812014-03-11 21:48:49 -070014using fw::Strategy;
15
16const ndn::Milliseconds Forwarder::DEFAULT_INTEREST_LIFETIME(static_cast<ndn::Milliseconds>(4000));
17const Name Forwarder::LOCALHOST_NAME("ndn:/localhost");
Junxiao Shi88884492014-02-15 15:57:43 -070018
Junxiao Shic041ca32014-02-25 20:01:15 -070019Forwarder::Forwarder()
Junxiao Shia4f2be82014-03-02 22:56:41 -070020 : m_faceTable(*this)
Haowei Yuan78c84d12014-02-27 15:35:13 -060021 , m_nameTree(1024) // "1024" could be made as one configurable parameter of the forwarder.
HangZhangad4afd12014-03-01 11:03:08 +080022 , m_fib(m_nameTree)
Haowei Yuan78c84d12014-02-27 15:35:13 -060023 , m_pit(m_nameTree)
HangZhangc85a23c2014-03-01 15:55:55 +080024 , m_measurements(m_nameTree)
Junxiao Shif3c07812014-03-11 21:48:49 -070025 , m_strategyChoice(m_nameTree, fw::makeDefaultStrategy(*this))
Alexander Afanasyev33b72772014-01-26 23:22:58 -080026{
Junxiao Shif3c07812014-03-11 21:48:49 -070027 fw::installStrategies(*this);
Alexander Afanasyev33b72772014-01-26 23:22:58 -080028}
29
30void
Junxiao Shid3c792f2014-01-30 00:46:13 -070031Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
32{
33 // receive Interest
Junxiao Shif3c07812014-03-11 21:48:49 -070034 NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() <<
35 " interest=" << interest.getName());
Junxiao Shi06887ac2014-02-13 20:15:42 -070036 const_cast<Interest&>(interest).setIncomingFaceId(inFace.getId());
Junxiao Shif3c07812014-03-11 21:48:49 -070037 if (interest.getInterestLifetime() < 0) {
38 const_cast<Interest&>(interest).setInterestLifetime(DEFAULT_INTEREST_LIFETIME);
39 }
Junxiao Shic041ca32014-02-25 20:01:15 -070040
Junxiao Shi88884492014-02-15 15:57:43 -070041 // /localhost scope control
Junxiao Shif3c07812014-03-11 21:48:49 -070042 bool isViolatingLocalhost = !inFace.isLocal() &&
43 LOCALHOST_NAME.isPrefixOf(interest.getName());
44 if (isViolatingLocalhost) {
45 NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() <<
46 " interest=" << interest.getName() << " violates /localhost");
47 // (drop)
Junxiao Shi88884492014-02-15 15:57:43 -070048 return;
49 }
Junxiao Shic041ca32014-02-25 20:01:15 -070050
Junxiao Shid3c792f2014-01-30 00:46:13 -070051 // PIT insert
Junxiao Shi40631842014-03-01 13:52:37 -070052 shared_ptr<pit::Entry> pitEntry = m_pit.insert(interest).first;
Junxiao Shic041ca32014-02-25 20:01:15 -070053
Junxiao Shid3c792f2014-01-30 00:46:13 -070054 // detect loop and record Nonce
55 bool isLoop = ! pitEntry->addNonce(interest.getNonce());
56 if (isLoop) {
57 // goto Interest loop pipeline
58 this->onInterestLoop(inFace, interest, pitEntry);
59 return;
60 }
Junxiao Shic041ca32014-02-25 20:01:15 -070061
Junxiao Shid3c792f2014-01-30 00:46:13 -070062 // cancel unsatisfy & straggler timer
63 this->cancelUnsatisfyAndStragglerTimer(pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -070064
Junxiao Shif3c07812014-03-11 21:48:49 -070065 // is pending?
Junxiao Shid3c792f2014-01-30 00:46:13 -070066 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
67 bool isPending = inRecords.begin() == inRecords.end();
Junxiao Shid3c792f2014-01-30 00:46:13 -070068 if (!isPending) {
69 // CS lookup
70 const Data* csMatch = m_cs.find(interest);
71 if (csMatch != 0) {
72 // XXX should we lookup PIT for other Interests that also match csMatch?
73
74 // goto outgoing Data pipeline
75 this->onOutgoingData(*csMatch, inFace);
76 return;
77 }
78 }
Junxiao Shic041ca32014-02-25 20:01:15 -070079
Junxiao Shid3c792f2014-01-30 00:46:13 -070080 // insert InRecord
Junxiao Shi9b27bd22014-02-26 20:29:58 -070081 pitEntry->insertOrUpdateInRecord(inFace.shared_from_this(), interest);
Junxiao Shic041ca32014-02-25 20:01:15 -070082
Junxiao Shid3c792f2014-01-30 00:46:13 -070083 // FIB lookup
Junxiao Shi40631842014-03-01 13:52:37 -070084 shared_ptr<fib::Entry> fibEntry = m_fib.findLongestPrefixMatch(*pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -070085
Junxiao Shid3c792f2014-01-30 00:46:13 -070086 // dispatch to strategy
Junxiao Shif3c07812014-03-11 21:48:49 -070087 this->dispatchToStrategy(pitEntry, bind(&Strategy::afterReceiveInterest, _1,
88 boost::cref(inFace), boost::cref(interest), fibEntry, pitEntry));
Junxiao Shid3c792f2014-01-30 00:46:13 -070089}
90
91void
92Forwarder::onInterestLoop(Face& inFace, const Interest& interest,
93 shared_ptr<pit::Entry> pitEntry)
94{
Junxiao Shif3c07812014-03-11 21:48:49 -070095 NFD_LOG_DEBUG("onInterestLoop face=" << inFace.getId() <<
96 " interest=" << interest.getName());
Junxiao Shi8c8d2182014-01-30 22:33:00 -070097
Junxiao Shif3c07812014-03-11 21:48:49 -070098 // (drop)
99}
100
101/** \brief compare two InRecords for picking outgoing Interest
102 * \return true if b is preferred over a
103 *
104 * This function should be passed to std::max_element over InRecordCollection.
105 * The outgoing Interest picked is the last incoming Interest
106 * that does not come from outFace.
107 * If all InRecords come from outFace, it's fine to pick that. This happens when
108 * there's only one InRecord that comes from outFace. The legit use is for
109 * vehicular network; otherwise, strategy shouldn't send to the sole inFace.
110 */
111static inline bool
112compare_pickInterest(const pit::InRecord& a, const pit::InRecord& b, const Face* outFace)
113{
114 bool isOutFaceA = a.getFace().get() == outFace;
115 bool isOutFaceB = b.getFace().get() == outFace;
116
117 if (!isOutFaceA && isOutFaceB) {
118 return false;
119 }
120 if (isOutFaceA && !isOutFaceB) {
121 return true;
122 }
123
124 return a.getLastRenewed() > b.getLastRenewed();
Junxiao Shid3c792f2014-01-30 00:46:13 -0700125}
126
127void
128Forwarder::onOutgoingInterest(shared_ptr<pit::Entry> pitEntry, Face& outFace)
129{
Junxiao Shif3c07812014-03-11 21:48:49 -0700130 NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() <<
131 " interest=" << pitEntry->getName());
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700132
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700133 // /localhost scope control
Junxiao Shif3c07812014-03-11 21:48:49 -0700134 bool isViolatingLocalhost = !outFace.isLocal() &&
135 LOCALHOST_NAME.isPrefixOf(pitEntry->getName());
136 if (isViolatingLocalhost) {
137 NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() <<
138 " interest=" << pitEntry->getName() << " violates /localhost");
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700139 return;
140 }
141
Junxiao Shid3c792f2014-01-30 00:46:13 -0700142 // pick Interest
Junxiao Shif3c07812014-03-11 21:48:49 -0700143 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
144 pit::InRecordCollection::const_iterator pickedInRecord = std::max_element(
145 inRecords.begin(), inRecords.end(), bind(&compare_pickInterest, _1, _2, &outFace));
146 BOOST_ASSERT(pickedInRecord != inRecords.end());
147 const Interest& interest = pickedInRecord->getInterest();
Junxiao Shic041ca32014-02-25 20:01:15 -0700148
Junxiao Shid3c792f2014-01-30 00:46:13 -0700149 // insert OutRecord
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700150 pitEntry->insertOrUpdateOutRecord(outFace.shared_from_this(), interest);
Junxiao Shic041ca32014-02-25 20:01:15 -0700151
Junxiao Shid3c792f2014-01-30 00:46:13 -0700152 // set PIT unsatisfy timer
153 this->setUnsatisfyTimer(pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -0700154
Junxiao Shid3c792f2014-01-30 00:46:13 -0700155 // send Interest
156 outFace.sendInterest(interest);
157}
158
159void
Junxiao Shi09498f02014-02-26 19:41:08 -0700160Forwarder::onInterestReject(shared_ptr<pit::Entry> pitEntry)
Junxiao Shid3c792f2014-01-30 00:46:13 -0700161{
Junxiao Shi09498f02014-02-26 19:41:08 -0700162 NFD_LOG_DEBUG("onInterestReject interest=" << pitEntry->getName());
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700163
Junxiao Shid3c792f2014-01-30 00:46:13 -0700164 // set PIT straggler timer
165 this->setStragglerTimer(pitEntry);
166}
167
168void
169Forwarder::onInterestUnsatisfied(shared_ptr<pit::Entry> pitEntry)
170{
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700171 NFD_LOG_DEBUG("onInterestUnsatisfied interest=" << pitEntry->getName());
172
Junxiao Shid3c792f2014-01-30 00:46:13 -0700173 // invoke PIT unsatisfied callback
Junxiao Shif3c07812014-03-11 21:48:49 -0700174 this->dispatchToStrategy(pitEntry, bind(&Strategy::beforeExpirePendingInterest, _1,
175 pitEntry));
Junxiao Shic041ca32014-02-25 20:01:15 -0700176
Junxiao Shif3c07812014-03-11 21:48:49 -0700177 // PIT delete
Haowei Yuan78c84d12014-02-27 15:35:13 -0600178 m_pit.erase(pitEntry);
Junxiao Shid3c792f2014-01-30 00:46:13 -0700179}
180
181void
182Forwarder::onIncomingData(Face& inFace, const Data& data)
183{
184 // receive Data
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700185 NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId() << " data=" << data.getName());
Junxiao Shi06887ac2014-02-13 20:15:42 -0700186 const_cast<Data&>(data).setIncomingFaceId(inFace.getId());
Junxiao Shic041ca32014-02-25 20:01:15 -0700187
Junxiao Shi88884492014-02-15 15:57:43 -0700188 // /localhost scope control
Junxiao Shif3c07812014-03-11 21:48:49 -0700189 bool isViolatingLocalhost = !inFace.isLocal() &&
190 LOCALHOST_NAME.isPrefixOf(data.getName());
191 if (isViolatingLocalhost) {
192 NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId() <<
193 " data=" << data.getName() << " violates /localhost");
194 // (drop)
Junxiao Shi88884492014-02-15 15:57:43 -0700195 return;
196 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700197
Junxiao Shid3c792f2014-01-30 00:46:13 -0700198 // PIT match
199 shared_ptr<pit::DataMatchResult> pitMatches = m_pit.findAllDataMatches(data);
200 if (pitMatches->begin() == pitMatches->end()) {
201 // goto Data unsolicited pipeline
202 this->onDataUnsolicited(inFace, data);
203 return;
204 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700205
Junxiao Shid3c792f2014-01-30 00:46:13 -0700206 // CS insert
207 m_cs.insert(data);
Junxiao Shic041ca32014-02-25 20:01:15 -0700208
Junxiao Shid3c792f2014-01-30 00:46:13 -0700209 std::set<shared_ptr<Face> > pendingDownstreams;
210 // foreach PitEntry
211 for (pit::DataMatchResult::iterator it = pitMatches->begin();
212 it != pitMatches->end(); ++it) {
213 shared_ptr<pit::Entry> pitEntry = *it;
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700214 NFD_LOG_DEBUG("onIncomingData matching=" << pitEntry->getName());
Junxiao Shic041ca32014-02-25 20:01:15 -0700215
Junxiao Shid3c792f2014-01-30 00:46:13 -0700216 // cancel unsatisfy & straggler timer
217 this->cancelUnsatisfyAndStragglerTimer(pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -0700218
Junxiao Shid3c792f2014-01-30 00:46:13 -0700219 // remember pending downstreams
220 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
221 for (pit::InRecordCollection::const_iterator it = inRecords.begin();
222 it != inRecords.end(); ++it) {
223 if (it->getExpiry() > time::now()) {
224 pendingDownstreams.insert(it->getFace());
225 }
226 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700227
Junxiao Shid3c792f2014-01-30 00:46:13 -0700228 // mark PIT satisfied
229 pitEntry->deleteInRecords();
230 pitEntry->deleteOutRecord(inFace.shared_from_this());
Junxiao Shic041ca32014-02-25 20:01:15 -0700231
Junxiao Shid3c792f2014-01-30 00:46:13 -0700232 // set PIT straggler timer
233 this->setStragglerTimer(pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -0700234
Junxiao Shid3c792f2014-01-30 00:46:13 -0700235 // invoke PIT satisfy callback
Junxiao Shif3c07812014-03-11 21:48:49 -0700236 this->dispatchToStrategy(pitEntry, bind(&Strategy::beforeSatisfyPendingInterest, _1,
237 pitEntry, boost::cref(inFace), boost::cref(data)));
Junxiao Shid3c792f2014-01-30 00:46:13 -0700238 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700239
Junxiao Shid3c792f2014-01-30 00:46:13 -0700240 // foreach pending downstream
241 for (std::set<shared_ptr<Face> >::iterator it = pendingDownstreams.begin();
242 it != pendingDownstreams.end(); ++it) {
243 // goto outgoing Data pipeline
244 this->onOutgoingData(data, **it);
245 }
246}
247
248void
249Forwarder::onDataUnsolicited(Face& inFace, const Data& data)
250{
251 // accept to cache?
Junxiao Shif3c07812014-03-11 21:48:49 -0700252 bool acceptToCache = inFace.isLocal();
Junxiao Shid3c792f2014-01-30 00:46:13 -0700253 if (acceptToCache) {
254 // CS insert
Junxiao Shif3c07812014-03-11 21:48:49 -0700255 m_cs.insert(data, true);
Junxiao Shid3c792f2014-01-30 00:46:13 -0700256 }
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700257
Junxiao Shif3c07812014-03-11 21:48:49 -0700258 NFD_LOG_DEBUG("onDataUnsolicited face=" << inFace.getId() <<
259 " data=" << data.getName() <<
260 (acceptToCache ? " cached" : " not cached"));
Junxiao Shid3c792f2014-01-30 00:46:13 -0700261}
262
263void
264Forwarder::onOutgoingData(const Data& data, Face& outFace)
265{
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700266 NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId() << " data=" << data.getName());
267
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700268 // /localhost scope control
Junxiao Shif3c07812014-03-11 21:48:49 -0700269 bool isViolatingLocalhost = !outFace.isLocal() &&
270 LOCALHOST_NAME.isPrefixOf(data.getName());
271 if (isViolatingLocalhost) {
272 NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId() <<
273 " data=" << data.getName() << " violates /localhost");
274 // (drop)
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700275 return;
276 }
277
Junxiao Shif3c07812014-03-11 21:48:49 -0700278 // TODO traffic manager
Junxiao Shic041ca32014-02-25 20:01:15 -0700279
Junxiao Shid3c792f2014-01-30 00:46:13 -0700280 // send Data
281 outFace.sendData(data);
282}
283
284static inline bool
285compare_InRecord_expiry(const pit::InRecord& a, const pit::InRecord& b)
286{
287 return a.getExpiry() < b.getExpiry();
288}
289
290void
291Forwarder::setUnsatisfyTimer(shared_ptr<pit::Entry> pitEntry)
292{
293 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
294 pit::InRecordCollection::const_iterator lastExpiring =
295 std::max_element(inRecords.begin(), inRecords.end(),
296 &compare_InRecord_expiry);
297
298 time::Point lastExpiry = lastExpiring->getExpiry();
299 time::Duration lastExpiryFromNow = lastExpiry - time::now();
300 if (lastExpiryFromNow <= time::seconds(0)) {
301 // TODO all InRecords are already expired; will this happen?
302 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700303
304 pitEntry->m_unsatisfyTimer = scheduler::schedule(lastExpiryFromNow,
Junxiao Shid3c792f2014-01-30 00:46:13 -0700305 bind(&Forwarder::onInterestUnsatisfied, this, pitEntry));
306}
307
308void
309Forwarder::setStragglerTimer(shared_ptr<pit::Entry> pitEntry)
310{
311 time::Duration stragglerTime = time::milliseconds(100);
Junxiao Shic041ca32014-02-25 20:01:15 -0700312
313 pitEntry->m_stragglerTimer = scheduler::schedule(stragglerTime,
Haowei Yuan78c84d12014-02-27 15:35:13 -0600314 bind(&Pit::erase, &m_pit, pitEntry));
Junxiao Shid3c792f2014-01-30 00:46:13 -0700315}
316
317void
318Forwarder::cancelUnsatisfyAndStragglerTimer(shared_ptr<pit::Entry> pitEntry)
319{
Junxiao Shic041ca32014-02-25 20:01:15 -0700320 scheduler::cancel(pitEntry->m_unsatisfyTimer);
321 scheduler::cancel(pitEntry->m_stragglerTimer);
Junxiao Shid3c792f2014-01-30 00:46:13 -0700322}
323
Alexander Afanasyev18bbf812014-01-29 01:40:23 -0800324} // namespace nfd