blob: a723a170fe24a64b57c2c789b4c55b45c6d126b8 [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 Shi11bd9c22014-03-13 20:44:13 -070018const Name Forwarder::LOCALHOP_NAME("ndn:/localhop");
Junxiao Shi88884492014-02-15 15:57:43 -070019
Junxiao Shic041ca32014-02-25 20:01:15 -070020Forwarder::Forwarder()
Junxiao Shia4f2be82014-03-02 22:56:41 -070021 : m_faceTable(*this)
Haowei Yuan78c84d12014-02-27 15:35:13 -060022 , m_nameTree(1024) // "1024" could be made as one configurable parameter of the forwarder.
HangZhangad4afd12014-03-01 11:03:08 +080023 , m_fib(m_nameTree)
Haowei Yuan78c84d12014-02-27 15:35:13 -060024 , m_pit(m_nameTree)
HangZhangc85a23c2014-03-01 15:55:55 +080025 , m_measurements(m_nameTree)
Junxiao Shif3c07812014-03-11 21:48:49 -070026 , m_strategyChoice(m_nameTree, fw::makeDefaultStrategy(*this))
Alexander Afanasyev33b72772014-01-26 23:22:58 -080027{
Junxiao Shif3c07812014-03-11 21:48:49 -070028 fw::installStrategies(*this);
Alexander Afanasyev33b72772014-01-26 23:22:58 -080029}
30
31void
Junxiao Shid3c792f2014-01-30 00:46:13 -070032Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
33{
34 // receive Interest
Junxiao Shif3c07812014-03-11 21:48:49 -070035 NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() <<
36 " interest=" << interest.getName());
Junxiao Shi06887ac2014-02-13 20:15:42 -070037 const_cast<Interest&>(interest).setIncomingFaceId(inFace.getId());
Junxiao Shif3c07812014-03-11 21:48:49 -070038 if (interest.getInterestLifetime() < 0) {
39 const_cast<Interest&>(interest).setInterestLifetime(DEFAULT_INTEREST_LIFETIME);
40 }
Junxiao Shib289cc12014-03-15 12:19:05 -070041 m_counters.getInInterest() ++;
Junxiao Shic041ca32014-02-25 20:01:15 -070042
Junxiao Shi88884492014-02-15 15:57:43 -070043 // /localhost scope control
Junxiao Shif3c07812014-03-11 21:48:49 -070044 bool isViolatingLocalhost = !inFace.isLocal() &&
45 LOCALHOST_NAME.isPrefixOf(interest.getName());
46 if (isViolatingLocalhost) {
47 NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() <<
48 " interest=" << interest.getName() << " violates /localhost");
49 // (drop)
Junxiao Shi88884492014-02-15 15:57:43 -070050 return;
51 }
Junxiao Shic041ca32014-02-25 20:01:15 -070052
Junxiao Shid3c792f2014-01-30 00:46:13 -070053 // PIT insert
Junxiao Shi40631842014-03-01 13:52:37 -070054 shared_ptr<pit::Entry> pitEntry = m_pit.insert(interest).first;
Junxiao Shic041ca32014-02-25 20:01:15 -070055
Junxiao Shid3c792f2014-01-30 00:46:13 -070056 // detect loop and record Nonce
57 bool isLoop = ! pitEntry->addNonce(interest.getNonce());
58 if (isLoop) {
59 // goto Interest loop pipeline
60 this->onInterestLoop(inFace, interest, pitEntry);
61 return;
62 }
Junxiao Shic041ca32014-02-25 20:01:15 -070063
Junxiao Shid3c792f2014-01-30 00:46:13 -070064 // cancel unsatisfy & straggler timer
65 this->cancelUnsatisfyAndStragglerTimer(pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -070066
Junxiao Shif3c07812014-03-11 21:48:49 -070067 // is pending?
Junxiao Shid3c792f2014-01-30 00:46:13 -070068 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
69 bool isPending = inRecords.begin() == inRecords.end();
Junxiao Shid3c792f2014-01-30 00:46:13 -070070 if (!isPending) {
71 // CS lookup
72 const Data* csMatch = m_cs.find(interest);
73 if (csMatch != 0) {
74 // XXX should we lookup PIT for other Interests that also match csMatch?
75
76 // goto outgoing Data pipeline
77 this->onOutgoingData(*csMatch, inFace);
78 return;
79 }
80 }
Junxiao Shic041ca32014-02-25 20:01:15 -070081
Junxiao Shid3c792f2014-01-30 00:46:13 -070082 // insert InRecord
Junxiao Shi9b27bd22014-02-26 20:29:58 -070083 pitEntry->insertOrUpdateInRecord(inFace.shared_from_this(), interest);
Junxiao Shic041ca32014-02-25 20:01:15 -070084
Junxiao Shid3c792f2014-01-30 00:46:13 -070085 // FIB lookup
Junxiao Shi40631842014-03-01 13:52:37 -070086 shared_ptr<fib::Entry> fibEntry = m_fib.findLongestPrefixMatch(*pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -070087
Junxiao Shid3c792f2014-01-30 00:46:13 -070088 // dispatch to strategy
Junxiao Shif3c07812014-03-11 21:48:49 -070089 this->dispatchToStrategy(pitEntry, bind(&Strategy::afterReceiveInterest, _1,
90 boost::cref(inFace), boost::cref(interest), fibEntry, pitEntry));
Junxiao Shid3c792f2014-01-30 00:46:13 -070091}
92
93void
94Forwarder::onInterestLoop(Face& inFace, const Interest& interest,
95 shared_ptr<pit::Entry> pitEntry)
96{
Junxiao Shif3c07812014-03-11 21:48:49 -070097 NFD_LOG_DEBUG("onInterestLoop face=" << inFace.getId() <<
98 " interest=" << interest.getName());
Junxiao Shi8c8d2182014-01-30 22:33:00 -070099
Junxiao Shif3c07812014-03-11 21:48:49 -0700100 // (drop)
101}
102
103/** \brief compare two InRecords for picking outgoing Interest
104 * \return true if b is preferred over a
105 *
106 * This function should be passed to std::max_element over InRecordCollection.
107 * The outgoing Interest picked is the last incoming Interest
108 * that does not come from outFace.
109 * If all InRecords come from outFace, it's fine to pick that. This happens when
110 * there's only one InRecord that comes from outFace. The legit use is for
111 * vehicular network; otherwise, strategy shouldn't send to the sole inFace.
112 */
113static inline bool
114compare_pickInterest(const pit::InRecord& a, const pit::InRecord& b, const Face* outFace)
115{
116 bool isOutFaceA = a.getFace().get() == outFace;
117 bool isOutFaceB = b.getFace().get() == outFace;
118
119 if (!isOutFaceA && isOutFaceB) {
120 return false;
121 }
122 if (isOutFaceA && !isOutFaceB) {
123 return true;
124 }
125
126 return a.getLastRenewed() > b.getLastRenewed();
Junxiao Shid3c792f2014-01-30 00:46:13 -0700127}
128
129void
130Forwarder::onOutgoingInterest(shared_ptr<pit::Entry> pitEntry, Face& outFace)
131{
Junxiao Shif3c07812014-03-11 21:48:49 -0700132 NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() <<
133 " interest=" << pitEntry->getName());
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700134
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700135 // /localhost scope control
Junxiao Shif3c07812014-03-11 21:48:49 -0700136 bool isViolatingLocalhost = !outFace.isLocal() &&
137 LOCALHOST_NAME.isPrefixOf(pitEntry->getName());
138 if (isViolatingLocalhost) {
139 NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() <<
140 " interest=" << pitEntry->getName() << " violates /localhost");
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700141 return;
142 }
143
Junxiao Shi11bd9c22014-03-13 20:44:13 -0700144 // /localhop scope control
145 bool isViolatingLocalhop = !outFace.isLocal() &&
146 LOCALHOP_NAME.isPrefixOf(pitEntry->getName()) &&
147 !pitEntry->hasLocalInRecord();
148 if (isViolatingLocalhop) {
149 NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() <<
150 " interest=" << pitEntry->getName() << " violates /localhop");
151 return;
152 }
153
Junxiao Shid3c792f2014-01-30 00:46:13 -0700154 // pick Interest
Junxiao Shif3c07812014-03-11 21:48:49 -0700155 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
156 pit::InRecordCollection::const_iterator pickedInRecord = std::max_element(
157 inRecords.begin(), inRecords.end(), bind(&compare_pickInterest, _1, _2, &outFace));
158 BOOST_ASSERT(pickedInRecord != inRecords.end());
159 const Interest& interest = pickedInRecord->getInterest();
Junxiao Shic041ca32014-02-25 20:01:15 -0700160
Junxiao Shid3c792f2014-01-30 00:46:13 -0700161 // insert OutRecord
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700162 pitEntry->insertOrUpdateOutRecord(outFace.shared_from_this(), interest);
Junxiao Shic041ca32014-02-25 20:01:15 -0700163
Junxiao Shid3c792f2014-01-30 00:46:13 -0700164 // set PIT unsatisfy timer
165 this->setUnsatisfyTimer(pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -0700166
Junxiao Shid3c792f2014-01-30 00:46:13 -0700167 // send Interest
168 outFace.sendInterest(interest);
Junxiao Shib289cc12014-03-15 12:19:05 -0700169 m_counters.getOutInterest() ++;
Junxiao Shid3c792f2014-01-30 00:46:13 -0700170}
171
172void
Junxiao Shi09498f02014-02-26 19:41:08 -0700173Forwarder::onInterestReject(shared_ptr<pit::Entry> pitEntry)
Junxiao Shid3c792f2014-01-30 00:46:13 -0700174{
Junxiao Shi09498f02014-02-26 19:41:08 -0700175 NFD_LOG_DEBUG("onInterestReject interest=" << pitEntry->getName());
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700176
Junxiao Shid3c792f2014-01-30 00:46:13 -0700177 // set PIT straggler timer
178 this->setStragglerTimer(pitEntry);
179}
180
181void
182Forwarder::onInterestUnsatisfied(shared_ptr<pit::Entry> pitEntry)
183{
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700184 NFD_LOG_DEBUG("onInterestUnsatisfied interest=" << pitEntry->getName());
185
Junxiao Shid3c792f2014-01-30 00:46:13 -0700186 // invoke PIT unsatisfied callback
Junxiao Shif3c07812014-03-11 21:48:49 -0700187 this->dispatchToStrategy(pitEntry, bind(&Strategy::beforeExpirePendingInterest, _1,
188 pitEntry));
Junxiao Shic041ca32014-02-25 20:01:15 -0700189
Junxiao Shif3c07812014-03-11 21:48:49 -0700190 // PIT delete
Haowei Yuan78c84d12014-02-27 15:35:13 -0600191 m_pit.erase(pitEntry);
Junxiao Shid3c792f2014-01-30 00:46:13 -0700192}
193
194void
195Forwarder::onIncomingData(Face& inFace, const Data& data)
196{
197 // receive Data
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700198 NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId() << " data=" << data.getName());
Junxiao Shi06887ac2014-02-13 20:15:42 -0700199 const_cast<Data&>(data).setIncomingFaceId(inFace.getId());
Junxiao Shib289cc12014-03-15 12:19:05 -0700200 m_counters.getInData() ++;
Junxiao Shic041ca32014-02-25 20:01:15 -0700201
Junxiao Shi88884492014-02-15 15:57:43 -0700202 // /localhost scope control
Junxiao Shif3c07812014-03-11 21:48:49 -0700203 bool isViolatingLocalhost = !inFace.isLocal() &&
204 LOCALHOST_NAME.isPrefixOf(data.getName());
205 if (isViolatingLocalhost) {
206 NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId() <<
207 " data=" << data.getName() << " violates /localhost");
208 // (drop)
Junxiao Shi88884492014-02-15 15:57:43 -0700209 return;
210 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700211
Junxiao Shid3c792f2014-01-30 00:46:13 -0700212 // PIT match
213 shared_ptr<pit::DataMatchResult> pitMatches = m_pit.findAllDataMatches(data);
214 if (pitMatches->begin() == pitMatches->end()) {
215 // goto Data unsolicited pipeline
216 this->onDataUnsolicited(inFace, data);
217 return;
218 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700219
Junxiao Shid3c792f2014-01-30 00:46:13 -0700220 // CS insert
221 m_cs.insert(data);
Junxiao Shic041ca32014-02-25 20:01:15 -0700222
Junxiao Shid3c792f2014-01-30 00:46:13 -0700223 std::set<shared_ptr<Face> > pendingDownstreams;
224 // foreach PitEntry
225 for (pit::DataMatchResult::iterator it = pitMatches->begin();
226 it != pitMatches->end(); ++it) {
227 shared_ptr<pit::Entry> pitEntry = *it;
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700228 NFD_LOG_DEBUG("onIncomingData matching=" << pitEntry->getName());
Junxiao Shic041ca32014-02-25 20:01:15 -0700229
Junxiao Shid3c792f2014-01-30 00:46:13 -0700230 // cancel unsatisfy & straggler timer
231 this->cancelUnsatisfyAndStragglerTimer(pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -0700232
Junxiao Shid3c792f2014-01-30 00:46:13 -0700233 // remember pending downstreams
234 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
235 for (pit::InRecordCollection::const_iterator it = inRecords.begin();
236 it != inRecords.end(); ++it) {
237 if (it->getExpiry() > time::now()) {
238 pendingDownstreams.insert(it->getFace());
239 }
240 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700241
Junxiao Shid3c792f2014-01-30 00:46:13 -0700242 // mark PIT satisfied
243 pitEntry->deleteInRecords();
244 pitEntry->deleteOutRecord(inFace.shared_from_this());
Junxiao Shic041ca32014-02-25 20:01:15 -0700245
Junxiao Shid3c792f2014-01-30 00:46:13 -0700246 // set PIT straggler timer
247 this->setStragglerTimer(pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -0700248
Junxiao Shid3c792f2014-01-30 00:46:13 -0700249 // invoke PIT satisfy callback
Junxiao Shif3c07812014-03-11 21:48:49 -0700250 this->dispatchToStrategy(pitEntry, bind(&Strategy::beforeSatisfyPendingInterest, _1,
251 pitEntry, boost::cref(inFace), boost::cref(data)));
Junxiao Shid3c792f2014-01-30 00:46:13 -0700252 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700253
Junxiao Shid3c792f2014-01-30 00:46:13 -0700254 // foreach pending downstream
255 for (std::set<shared_ptr<Face> >::iterator it = pendingDownstreams.begin();
256 it != pendingDownstreams.end(); ++it) {
257 // goto outgoing Data pipeline
258 this->onOutgoingData(data, **it);
259 }
260}
261
262void
263Forwarder::onDataUnsolicited(Face& inFace, const Data& data)
264{
265 // accept to cache?
Junxiao Shif3c07812014-03-11 21:48:49 -0700266 bool acceptToCache = inFace.isLocal();
Junxiao Shid3c792f2014-01-30 00:46:13 -0700267 if (acceptToCache) {
268 // CS insert
Junxiao Shif3c07812014-03-11 21:48:49 -0700269 m_cs.insert(data, true);
Junxiao Shid3c792f2014-01-30 00:46:13 -0700270 }
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700271
Junxiao Shif3c07812014-03-11 21:48:49 -0700272 NFD_LOG_DEBUG("onDataUnsolicited face=" << inFace.getId() <<
273 " data=" << data.getName() <<
274 (acceptToCache ? " cached" : " not cached"));
Junxiao Shid3c792f2014-01-30 00:46:13 -0700275}
276
277void
278Forwarder::onOutgoingData(const Data& data, Face& outFace)
279{
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700280 NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId() << " data=" << data.getName());
281
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700282 // /localhost scope control
Junxiao Shif3c07812014-03-11 21:48:49 -0700283 bool isViolatingLocalhost = !outFace.isLocal() &&
284 LOCALHOST_NAME.isPrefixOf(data.getName());
285 if (isViolatingLocalhost) {
286 NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId() <<
287 " data=" << data.getName() << " violates /localhost");
288 // (drop)
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700289 return;
290 }
291
Junxiao Shif3c07812014-03-11 21:48:49 -0700292 // TODO traffic manager
Junxiao Shic041ca32014-02-25 20:01:15 -0700293
Junxiao Shid3c792f2014-01-30 00:46:13 -0700294 // send Data
295 outFace.sendData(data);
Junxiao Shib289cc12014-03-15 12:19:05 -0700296 m_counters.getOutData() ++;
Junxiao Shid3c792f2014-01-30 00:46:13 -0700297}
298
299static inline bool
300compare_InRecord_expiry(const pit::InRecord& a, const pit::InRecord& b)
301{
302 return a.getExpiry() < b.getExpiry();
303}
304
305void
306Forwarder::setUnsatisfyTimer(shared_ptr<pit::Entry> pitEntry)
307{
308 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
309 pit::InRecordCollection::const_iterator lastExpiring =
310 std::max_element(inRecords.begin(), inRecords.end(),
311 &compare_InRecord_expiry);
312
313 time::Point lastExpiry = lastExpiring->getExpiry();
314 time::Duration lastExpiryFromNow = lastExpiry - time::now();
315 if (lastExpiryFromNow <= time::seconds(0)) {
316 // TODO all InRecords are already expired; will this happen?
317 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700318
319 pitEntry->m_unsatisfyTimer = scheduler::schedule(lastExpiryFromNow,
Junxiao Shid3c792f2014-01-30 00:46:13 -0700320 bind(&Forwarder::onInterestUnsatisfied, this, pitEntry));
321}
322
323void
324Forwarder::setStragglerTimer(shared_ptr<pit::Entry> pitEntry)
325{
326 time::Duration stragglerTime = time::milliseconds(100);
Junxiao Shic041ca32014-02-25 20:01:15 -0700327
328 pitEntry->m_stragglerTimer = scheduler::schedule(stragglerTime,
Haowei Yuan78c84d12014-02-27 15:35:13 -0600329 bind(&Pit::erase, &m_pit, pitEntry));
Junxiao Shid3c792f2014-01-30 00:46:13 -0700330}
331
332void
333Forwarder::cancelUnsatisfyAndStragglerTimer(shared_ptr<pit::Entry> pitEntry)
334{
Junxiao Shic041ca32014-02-25 20:01:15 -0700335 scheduler::cancel(pitEntry->m_unsatisfyTimer);
336 scheduler::cancel(pitEntry->m_stragglerTimer);
Junxiao Shid3c792f2014-01-30 00:46:13 -0700337}
338
Alexander Afanasyev18bbf812014-01-29 01:40:23 -0800339} // namespace nfd