blob: 6c9f3ce33e35047dd1da5eb086b3313783a15b79 [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 Shi8c8d2182014-01-30 22:33:00 -07008#include "core/logger.hpp"
9#include "best-route-strategy.hpp"
Alexander Afanasyev33b72772014-01-26 23:22:58 -080010
Alexander Afanasyev18bbf812014-01-29 01:40:23 -080011namespace nfd {
Alexander Afanasyev33b72772014-01-26 23:22:58 -080012
Junxiao Shi8c8d2182014-01-30 22:33:00 -070013NFD_LOG_INIT("Forwarder");
14
Junxiao Shi88884492014-02-15 15:57:43 -070015const Name Forwarder::s_localhostName("ndn:/localhost");
16
Junxiao Shic041ca32014-02-25 20:01:15 -070017Forwarder::Forwarder()
Junxiao Shia4f2be82014-03-02 22:56:41 -070018 : m_faceTable(*this)
Haowei Yuan78c84d12014-02-27 15:35:13 -060019 , m_nameTree(1024) // "1024" could be made as one configurable parameter of the forwarder.
HangZhangad4afd12014-03-01 11:03:08 +080020 , m_fib(m_nameTree)
Haowei Yuan78c84d12014-02-27 15:35:13 -060021 , m_pit(m_nameTree)
HangZhangc85a23c2014-03-01 15:55:55 +080022 , m_measurements(m_nameTree)
Junxiao Shibb5105f2014-03-03 12:06:45 -070023 , m_strategyChoice(m_nameTree, make_shared<fw::BestRouteStrategy>(boost::ref(*this)))
Alexander Afanasyev33b72772014-01-26 23:22:58 -080024{
Junxiao Shi8c8d2182014-01-30 22:33:00 -070025 m_strategy = make_shared<fw::BestRouteStrategy>(boost::ref(*this));
Alexander Afanasyev33b72772014-01-26 23:22:58 -080026}
27
28void
Junxiao Shid3c792f2014-01-30 00:46:13 -070029Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
30{
31 // receive Interest
Junxiao Shi8c8d2182014-01-30 22:33:00 -070032 NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() << " interest=" << interest.getName());
Junxiao Shi06887ac2014-02-13 20:15:42 -070033 const_cast<Interest&>(interest).setIncomingFaceId(inFace.getId());
Junxiao Shic041ca32014-02-25 20:01:15 -070034
Junxiao Shi88884492014-02-15 15:57:43 -070035 // /localhost scope control
36 bool violatesLocalhost = !inFace.isLocal() &&
37 s_localhostName.isPrefixOf(interest.getName());
38 if (violatesLocalhost) {
39 NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId()
40 << " interest=" << interest.getName() << " violates /localhost");
41 return;
42 }
Junxiao Shic041ca32014-02-25 20:01:15 -070043
Junxiao Shid3c792f2014-01-30 00:46:13 -070044 // PIT insert
Junxiao Shi40631842014-03-01 13:52:37 -070045 shared_ptr<pit::Entry> pitEntry = m_pit.insert(interest).first;
Junxiao Shic041ca32014-02-25 20:01:15 -070046
Junxiao Shid3c792f2014-01-30 00:46:13 -070047 // detect loop and record Nonce
48 bool isLoop = ! pitEntry->addNonce(interest.getNonce());
49 if (isLoop) {
50 // goto Interest loop pipeline
51 this->onInterestLoop(inFace, interest, pitEntry);
52 return;
53 }
Junxiao Shic041ca32014-02-25 20:01:15 -070054
Junxiao Shid3c792f2014-01-30 00:46:13 -070055 // cancel unsatisfy & straggler timer
56 this->cancelUnsatisfyAndStragglerTimer(pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -070057
Junxiao Shid3c792f2014-01-30 00:46:13 -070058 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
59 bool isPending = inRecords.begin() == inRecords.end();
Junxiao Shic041ca32014-02-25 20:01:15 -070060
Junxiao Shid3c792f2014-01-30 00:46:13 -070061 if (!isPending) {
62 // CS lookup
63 const Data* csMatch = m_cs.find(interest);
64 if (csMatch != 0) {
65 // XXX should we lookup PIT for other Interests that also match csMatch?
66
67 // goto outgoing Data pipeline
68 this->onOutgoingData(*csMatch, inFace);
69 return;
70 }
71 }
Junxiao Shic041ca32014-02-25 20:01:15 -070072
Junxiao Shid3c792f2014-01-30 00:46:13 -070073 // insert InRecord
Junxiao Shi9b27bd22014-02-26 20:29:58 -070074 pitEntry->insertOrUpdateInRecord(inFace.shared_from_this(), interest);
Junxiao Shic041ca32014-02-25 20:01:15 -070075
Junxiao Shid3c792f2014-01-30 00:46:13 -070076 // app chosen nexthops
77 bool isAppChosenNexthops = false; // TODO get from local control header
78 if (isAppChosenNexthops) {
79 // TODO foreach chosen nexthop: goto outgoing Interest pipeline
80 return;
81 }
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 Shi88884492014-02-15 15:57:43 -070087 this->dispatchToStrategy(inFace, interest, fibEntry, pitEntry);
Junxiao Shid3c792f2014-01-30 00:46:13 -070088}
89
90void
91Forwarder::onInterestLoop(Face& inFace, const Interest& interest,
92 shared_ptr<pit::Entry> pitEntry)
93{
Junxiao Shi8c8d2182014-01-30 22:33:00 -070094 NFD_LOG_DEBUG("onInterestLoop face=" << inFace.getId() << " interest=" << interest.getName());
95
Junxiao Shid3c792f2014-01-30 00:46:13 -070096 // do nothing, which means Interest is dropped
97}
98
99void
100Forwarder::onOutgoingInterest(shared_ptr<pit::Entry> pitEntry, Face& outFace)
101{
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700102 NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() << " interest=" << pitEntry->getName());
103
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700104 // /localhost scope control
105 bool violatesLocalhost = !outFace.isLocal() &&
106 s_localhostName.isPrefixOf(pitEntry->getName());
107 if (violatesLocalhost) {
108 NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId()
109 << " interest=" << pitEntry->getName() << " violates /localhost");
110 return;
111 }
112
Junxiao Shid3c792f2014-01-30 00:46:13 -0700113 // pick Interest
114 const Interest& interest = pitEntry->getInterest();
115 // TODO pick the last incoming Interest
Junxiao Shic041ca32014-02-25 20:01:15 -0700116
Junxiao Shid3c792f2014-01-30 00:46:13 -0700117 // insert OutRecord
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700118 pitEntry->insertOrUpdateOutRecord(outFace.shared_from_this(), interest);
Junxiao Shic041ca32014-02-25 20:01:15 -0700119
Junxiao Shid3c792f2014-01-30 00:46:13 -0700120 // set PIT unsatisfy timer
121 this->setUnsatisfyTimer(pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -0700122
Junxiao Shid3c792f2014-01-30 00:46:13 -0700123 // send Interest
124 outFace.sendInterest(interest);
125}
126
127void
Junxiao Shi09498f02014-02-26 19:41:08 -0700128Forwarder::onInterestReject(shared_ptr<pit::Entry> pitEntry)
Junxiao Shid3c792f2014-01-30 00:46:13 -0700129{
Junxiao Shi09498f02014-02-26 19:41:08 -0700130 NFD_LOG_DEBUG("onInterestReject interest=" << pitEntry->getName());
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700131
Junxiao Shid3c792f2014-01-30 00:46:13 -0700132 // set PIT straggler timer
133 this->setStragglerTimer(pitEntry);
134}
135
136void
137Forwarder::onInterestUnsatisfied(shared_ptr<pit::Entry> pitEntry)
138{
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700139 NFD_LOG_DEBUG("onInterestUnsatisfied interest=" << pitEntry->getName());
140
Junxiao Shid3c792f2014-01-30 00:46:13 -0700141 // invoke PIT unsatisfied callback
142 // TODO
Junxiao Shic041ca32014-02-25 20:01:15 -0700143
Haowei Yuan78c84d12014-02-27 15:35:13 -0600144 // PIT erase
145 m_pit.erase(pitEntry);
Junxiao Shid3c792f2014-01-30 00:46:13 -0700146}
147
148void
149Forwarder::onIncomingData(Face& inFace, const Data& data)
150{
151 // receive Data
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700152 NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId() << " data=" << data.getName());
Junxiao Shi06887ac2014-02-13 20:15:42 -0700153 const_cast<Data&>(data).setIncomingFaceId(inFace.getId());
Junxiao Shic041ca32014-02-25 20:01:15 -0700154
Junxiao Shi88884492014-02-15 15:57:43 -0700155 // /localhost scope control
156 bool violatesLocalhost = !inFace.isLocal() &&
157 s_localhostName.isPrefixOf(data.getName());
158 if (violatesLocalhost) {
159 NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId()
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700160 << " data=" << data.getName() << " violates /localhost");
Junxiao Shi88884492014-02-15 15:57:43 -0700161 return;
162 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700163
Junxiao Shid3c792f2014-01-30 00:46:13 -0700164 // PIT match
165 shared_ptr<pit::DataMatchResult> pitMatches = m_pit.findAllDataMatches(data);
166 if (pitMatches->begin() == pitMatches->end()) {
167 // goto Data unsolicited pipeline
168 this->onDataUnsolicited(inFace, data);
169 return;
170 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700171
Junxiao Shid3c792f2014-01-30 00:46:13 -0700172 // CS insert
173 m_cs.insert(data);
Junxiao Shic041ca32014-02-25 20:01:15 -0700174
Junxiao Shid3c792f2014-01-30 00:46:13 -0700175 std::set<shared_ptr<Face> > pendingDownstreams;
176 // foreach PitEntry
177 for (pit::DataMatchResult::iterator it = pitMatches->begin();
178 it != pitMatches->end(); ++it) {
179 shared_ptr<pit::Entry> pitEntry = *it;
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700180 NFD_LOG_DEBUG("onIncomingData matching=" << pitEntry->getName());
Junxiao Shic041ca32014-02-25 20:01:15 -0700181
Junxiao Shid3c792f2014-01-30 00:46:13 -0700182 // cancel unsatisfy & straggler timer
183 this->cancelUnsatisfyAndStragglerTimer(pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -0700184
Junxiao Shid3c792f2014-01-30 00:46:13 -0700185 // remember pending downstreams
186 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
187 for (pit::InRecordCollection::const_iterator it = inRecords.begin();
188 it != inRecords.end(); ++it) {
189 if (it->getExpiry() > time::now()) {
190 pendingDownstreams.insert(it->getFace());
191 }
192 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700193
Junxiao Shid3c792f2014-01-30 00:46:13 -0700194 // mark PIT satisfied
195 pitEntry->deleteInRecords();
196 pitEntry->deleteOutRecord(inFace.shared_from_this());
Junxiao Shic041ca32014-02-25 20:01:15 -0700197
Junxiao Shid3c792f2014-01-30 00:46:13 -0700198 // set PIT straggler timer
199 this->setStragglerTimer(pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -0700200
Junxiao Shid3c792f2014-01-30 00:46:13 -0700201 // invoke PIT satisfy callback
202 // TODO
203 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700204
Junxiao Shid3c792f2014-01-30 00:46:13 -0700205 // foreach pending downstream
206 for (std::set<shared_ptr<Face> >::iterator it = pendingDownstreams.begin();
207 it != pendingDownstreams.end(); ++it) {
208 // goto outgoing Data pipeline
209 this->onOutgoingData(data, **it);
210 }
211}
212
213void
214Forwarder::onDataUnsolicited(Face& inFace, const Data& data)
215{
216 // accept to cache?
217 bool acceptToCache = false;// TODO decision
218 if (acceptToCache) {
219 // CS insert
220 m_cs.insert(data);
221 }
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700222
223 NFD_LOG_DEBUG("onDataUnsolicited face=" << inFace.getId() << " data=" << data.getName() << " acceptToCache=" << acceptToCache);
Junxiao Shid3c792f2014-01-30 00:46:13 -0700224}
225
226void
227Forwarder::onOutgoingData(const Data& data, Face& outFace)
228{
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700229 NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId() << " data=" << data.getName());
230
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700231 // /localhost scope control
232 bool violatesLocalhost = !outFace.isLocal() &&
233 s_localhostName.isPrefixOf(data.getName());
234 if (violatesLocalhost) {
235 NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId()
236 << " data=" << data.getName() << " violates /localhost");
237 return;
238 }
239
Junxiao Shid3c792f2014-01-30 00:46:13 -0700240 // traffic manager
241 // pass through
Junxiao Shic041ca32014-02-25 20:01:15 -0700242
Junxiao Shid3c792f2014-01-30 00:46:13 -0700243 // send Data
244 outFace.sendData(data);
245}
246
247static inline bool
248compare_InRecord_expiry(const pit::InRecord& a, const pit::InRecord& b)
249{
250 return a.getExpiry() < b.getExpiry();
251}
252
253void
254Forwarder::setUnsatisfyTimer(shared_ptr<pit::Entry> pitEntry)
255{
256 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
257 pit::InRecordCollection::const_iterator lastExpiring =
258 std::max_element(inRecords.begin(), inRecords.end(),
259 &compare_InRecord_expiry);
260
261 time::Point lastExpiry = lastExpiring->getExpiry();
262 time::Duration lastExpiryFromNow = lastExpiry - time::now();
263 if (lastExpiryFromNow <= time::seconds(0)) {
264 // TODO all InRecords are already expired; will this happen?
265 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700266
267 pitEntry->m_unsatisfyTimer = scheduler::schedule(lastExpiryFromNow,
Junxiao Shid3c792f2014-01-30 00:46:13 -0700268 bind(&Forwarder::onInterestUnsatisfied, this, pitEntry));
269}
270
271void
272Forwarder::setStragglerTimer(shared_ptr<pit::Entry> pitEntry)
273{
274 time::Duration stragglerTime = time::milliseconds(100);
Junxiao Shic041ca32014-02-25 20:01:15 -0700275
276 pitEntry->m_stragglerTimer = scheduler::schedule(stragglerTime,
Haowei Yuan78c84d12014-02-27 15:35:13 -0600277 bind(&Pit::erase, &m_pit, pitEntry));
Junxiao Shid3c792f2014-01-30 00:46:13 -0700278}
279
280void
281Forwarder::cancelUnsatisfyAndStragglerTimer(shared_ptr<pit::Entry> pitEntry)
282{
Junxiao Shic041ca32014-02-25 20:01:15 -0700283 scheduler::cancel(pitEntry->m_unsatisfyTimer);
284 scheduler::cancel(pitEntry->m_stragglerTimer);
Junxiao Shid3c792f2014-01-30 00:46:13 -0700285}
286
Junxiao Shi88884492014-02-15 15:57:43 -0700287void
288Forwarder::dispatchToStrategy(const Face& inFace,
289 const Interest& interest,
290 shared_ptr<fib::Entry> fibEntry,
291 shared_ptr<pit::Entry> pitEntry)
292{
293 m_strategy->afterReceiveInterest(inFace, interest, fibEntry, pitEntry);
294 // TODO dispatch according to fibEntry
295}
Junxiao Shid3c792f2014-01-30 00:46:13 -0700296
Alexander Afanasyev18bbf812014-01-29 01:40:23 -0800297} // namespace nfd