blob: 417a4cbd1d351920ecd1d7c373a64679c46e907e [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()
18 : m_lastFaceId(0)
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)
Alexander Afanasyev33b72772014-01-26 23:22:58 -080023{
Junxiao Shi8c8d2182014-01-30 22:33:00 -070024 m_strategy = make_shared<fw::BestRouteStrategy>(boost::ref(*this));
Alexander Afanasyev33b72772014-01-26 23:22:58 -080025}
26
27void
Junxiao Shi8c8d2182014-01-30 22:33:00 -070028Forwarder::addFace(shared_ptr<Face> face)
Alexander Afanasyev33b72772014-01-26 23:22:58 -080029{
Junxiao Shi8c8d2182014-01-30 22:33:00 -070030 FaceId faceId = ++m_lastFaceId;
31 face->setId(faceId);
32 m_faces[faceId] = face;
33 NFD_LOG_INFO("addFace id=" << faceId);
34
35 face->onReceiveInterest += bind(&Forwarder::onInterest,
36 this, boost::ref(*face), _1);
37 face->onReceiveData += bind(&Forwarder::onData,
38 this, boost::ref(*face), _1);
Alexander Afanasyev33b72772014-01-26 23:22:58 -080039}
40
41void
Junxiao Shi8c8d2182014-01-30 22:33:00 -070042Forwarder::removeFace(shared_ptr<Face> face)
Alexander Afanasyev33b72772014-01-26 23:22:58 -080043{
Junxiao Shi8c8d2182014-01-30 22:33:00 -070044 FaceId faceId = face->getId();
45 m_faces.erase(faceId);
46 face->setId(INVALID_FACEID);
47 NFD_LOG_INFO("removeFace id=" << faceId);
Junxiao Shic041ca32014-02-25 20:01:15 -070048
Junxiao Shi8c8d2182014-01-30 22:33:00 -070049 // XXX This clears all subscriptions, because EventEmitter
50 // does not support only removing Forwarder's subscription
51 face->onReceiveInterest.clear();
52 face->onReceiveData .clear();
Junxiao Shic041ca32014-02-25 20:01:15 -070053
Junxiao Shi8c8d2182014-01-30 22:33:00 -070054 m_fib.removeNextHopFromAllEntries(face);
Alexander Afanasyev33b72772014-01-26 23:22:58 -080055}
56
Steve DiBenedetto26b730f2014-02-02 18:36:16 -070057shared_ptr<Face>
58Forwarder::getFace(FaceId id)
59{
60 std::map<FaceId, shared_ptr<Face> >::iterator i = m_faces.find(id);
61 return (i == m_faces.end()) ? (shared_ptr<Face>()) : (i->second);
62}
63
Alexander Afanasyev33b72772014-01-26 23:22:58 -080064void
Junxiao Shi8c8d2182014-01-30 22:33:00 -070065Forwarder::onInterest(Face& face, const Interest& interest)
Alexander Afanasyev33b72772014-01-26 23:22:58 -080066{
Junxiao Shi8c8d2182014-01-30 22:33:00 -070067 this->onIncomingInterest(face, interest);
68}
69
70void
71Forwarder::onData(Face& face, const Data& data)
72{
73 this->onIncomingData(face, data);
Alexander Afanasyev33b72772014-01-26 23:22:58 -080074}
75
Junxiao Shid3c792f2014-01-30 00:46:13 -070076void
77Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
78{
79 // receive Interest
Junxiao Shi8c8d2182014-01-30 22:33:00 -070080 NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() << " interest=" << interest.getName());
Junxiao Shi06887ac2014-02-13 20:15:42 -070081 const_cast<Interest&>(interest).setIncomingFaceId(inFace.getId());
Junxiao Shic041ca32014-02-25 20:01:15 -070082
Junxiao Shi88884492014-02-15 15:57:43 -070083 // /localhost scope control
84 bool violatesLocalhost = !inFace.isLocal() &&
85 s_localhostName.isPrefixOf(interest.getName());
86 if (violatesLocalhost) {
87 NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId()
88 << " interest=" << interest.getName() << " violates /localhost");
89 return;
90 }
Junxiao Shic041ca32014-02-25 20:01:15 -070091
Junxiao Shid3c792f2014-01-30 00:46:13 -070092 // PIT insert
93 std::pair<shared_ptr<pit::Entry>, bool>
94 pitInsertResult = m_pit.insert(interest);
95 shared_ptr<pit::Entry> pitEntry = pitInsertResult.first;
Junxiao Shic041ca32014-02-25 20:01:15 -070096
Junxiao Shid3c792f2014-01-30 00:46:13 -070097 // detect loop and record Nonce
98 bool isLoop = ! pitEntry->addNonce(interest.getNonce());
99 if (isLoop) {
100 // goto Interest loop pipeline
101 this->onInterestLoop(inFace, interest, pitEntry);
102 return;
103 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700104
Junxiao Shid3c792f2014-01-30 00:46:13 -0700105 // cancel unsatisfy & straggler timer
106 this->cancelUnsatisfyAndStragglerTimer(pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -0700107
Junxiao Shid3c792f2014-01-30 00:46:13 -0700108 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
109 bool isPending = inRecords.begin() == inRecords.end();
Junxiao Shic041ca32014-02-25 20:01:15 -0700110
Junxiao Shid3c792f2014-01-30 00:46:13 -0700111 if (!isPending) {
112 // CS lookup
113 const Data* csMatch = m_cs.find(interest);
114 if (csMatch != 0) {
115 // XXX should we lookup PIT for other Interests that also match csMatch?
116
117 // goto outgoing Data pipeline
118 this->onOutgoingData(*csMatch, inFace);
119 return;
120 }
121 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700122
Junxiao Shid3c792f2014-01-30 00:46:13 -0700123 // insert InRecord
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700124 pitEntry->insertOrUpdateInRecord(inFace.shared_from_this(), interest);
Junxiao Shic041ca32014-02-25 20:01:15 -0700125
Junxiao Shid3c792f2014-01-30 00:46:13 -0700126 // app chosen nexthops
127 bool isAppChosenNexthops = false; // TODO get from local control header
128 if (isAppChosenNexthops) {
129 // TODO foreach chosen nexthop: goto outgoing Interest pipeline
130 return;
131 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700132
Junxiao Shid3c792f2014-01-30 00:46:13 -0700133 // FIB lookup
134 shared_ptr<fib::Entry> fibEntry
135 = m_fib.findLongestPrefixMatch(interest.getName());
136 // TODO use Fib::findParent(pitEntry)
Junxiao Shic041ca32014-02-25 20:01:15 -0700137
Junxiao Shid3c792f2014-01-30 00:46:13 -0700138 // dispatch to strategy
Junxiao Shi88884492014-02-15 15:57:43 -0700139 this->dispatchToStrategy(inFace, interest, fibEntry, pitEntry);
Junxiao Shid3c792f2014-01-30 00:46:13 -0700140}
141
142void
143Forwarder::onInterestLoop(Face& inFace, const Interest& interest,
144 shared_ptr<pit::Entry> pitEntry)
145{
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700146 NFD_LOG_DEBUG("onInterestLoop face=" << inFace.getId() << " interest=" << interest.getName());
147
Junxiao Shid3c792f2014-01-30 00:46:13 -0700148 // do nothing, which means Interest is dropped
149}
150
151void
152Forwarder::onOutgoingInterest(shared_ptr<pit::Entry> pitEntry, Face& outFace)
153{
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700154 NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() << " interest=" << pitEntry->getName());
155
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700156 // /localhost scope control
157 bool violatesLocalhost = !outFace.isLocal() &&
158 s_localhostName.isPrefixOf(pitEntry->getName());
159 if (violatesLocalhost) {
160 NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId()
161 << " interest=" << pitEntry->getName() << " violates /localhost");
162 return;
163 }
164
Junxiao Shid3c792f2014-01-30 00:46:13 -0700165 // pick Interest
166 const Interest& interest = pitEntry->getInterest();
167 // TODO pick the last incoming Interest
Junxiao Shic041ca32014-02-25 20:01:15 -0700168
Junxiao Shid3c792f2014-01-30 00:46:13 -0700169 // insert OutRecord
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700170 pitEntry->insertOrUpdateOutRecord(outFace.shared_from_this(), interest);
Junxiao Shic041ca32014-02-25 20:01:15 -0700171
Junxiao Shid3c792f2014-01-30 00:46:13 -0700172 // set PIT unsatisfy timer
173 this->setUnsatisfyTimer(pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -0700174
Junxiao Shid3c792f2014-01-30 00:46:13 -0700175 // send Interest
176 outFace.sendInterest(interest);
177}
178
179void
Junxiao Shi09498f02014-02-26 19:41:08 -0700180Forwarder::onInterestReject(shared_ptr<pit::Entry> pitEntry)
Junxiao Shid3c792f2014-01-30 00:46:13 -0700181{
Junxiao Shi09498f02014-02-26 19:41:08 -0700182 NFD_LOG_DEBUG("onInterestReject interest=" << pitEntry->getName());
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700183
Junxiao Shid3c792f2014-01-30 00:46:13 -0700184 // set PIT straggler timer
185 this->setStragglerTimer(pitEntry);
186}
187
188void
189Forwarder::onInterestUnsatisfied(shared_ptr<pit::Entry> pitEntry)
190{
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700191 NFD_LOG_DEBUG("onInterestUnsatisfied interest=" << pitEntry->getName());
192
Junxiao Shid3c792f2014-01-30 00:46:13 -0700193 // invoke PIT unsatisfied callback
194 // TODO
Junxiao Shic041ca32014-02-25 20:01:15 -0700195
Haowei Yuan78c84d12014-02-27 15:35:13 -0600196 // PIT erase
197 m_pit.erase(pitEntry);
Junxiao Shid3c792f2014-01-30 00:46:13 -0700198}
199
200void
201Forwarder::onIncomingData(Face& inFace, const Data& data)
202{
203 // receive Data
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700204 NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId() << " data=" << data.getName());
Junxiao Shi06887ac2014-02-13 20:15:42 -0700205 const_cast<Data&>(data).setIncomingFaceId(inFace.getId());
Junxiao Shic041ca32014-02-25 20:01:15 -0700206
Junxiao Shi88884492014-02-15 15:57:43 -0700207 // /localhost scope control
208 bool violatesLocalhost = !inFace.isLocal() &&
209 s_localhostName.isPrefixOf(data.getName());
210 if (violatesLocalhost) {
211 NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId()
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700212 << " data=" << data.getName() << " violates /localhost");
Junxiao Shi88884492014-02-15 15:57:43 -0700213 return;
214 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700215
Junxiao Shid3c792f2014-01-30 00:46:13 -0700216 // PIT match
217 shared_ptr<pit::DataMatchResult> pitMatches = m_pit.findAllDataMatches(data);
218 if (pitMatches->begin() == pitMatches->end()) {
219 // goto Data unsolicited pipeline
220 this->onDataUnsolicited(inFace, data);
221 return;
222 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700223
Junxiao Shid3c792f2014-01-30 00:46:13 -0700224 // CS insert
225 m_cs.insert(data);
Junxiao Shic041ca32014-02-25 20:01:15 -0700226
Junxiao Shid3c792f2014-01-30 00:46:13 -0700227 std::set<shared_ptr<Face> > pendingDownstreams;
228 // foreach PitEntry
229 for (pit::DataMatchResult::iterator it = pitMatches->begin();
230 it != pitMatches->end(); ++it) {
231 shared_ptr<pit::Entry> pitEntry = *it;
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700232 NFD_LOG_DEBUG("onIncomingData matching=" << pitEntry->getName());
Junxiao Shic041ca32014-02-25 20:01:15 -0700233
Junxiao Shid3c792f2014-01-30 00:46:13 -0700234 // cancel unsatisfy & straggler timer
235 this->cancelUnsatisfyAndStragglerTimer(pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -0700236
Junxiao Shid3c792f2014-01-30 00:46:13 -0700237 // remember pending downstreams
238 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
239 for (pit::InRecordCollection::const_iterator it = inRecords.begin();
240 it != inRecords.end(); ++it) {
241 if (it->getExpiry() > time::now()) {
242 pendingDownstreams.insert(it->getFace());
243 }
244 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700245
Junxiao Shid3c792f2014-01-30 00:46:13 -0700246 // mark PIT satisfied
247 pitEntry->deleteInRecords();
248 pitEntry->deleteOutRecord(inFace.shared_from_this());
Junxiao Shic041ca32014-02-25 20:01:15 -0700249
Junxiao Shid3c792f2014-01-30 00:46:13 -0700250 // set PIT straggler timer
251 this->setStragglerTimer(pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -0700252
Junxiao Shid3c792f2014-01-30 00:46:13 -0700253 // invoke PIT satisfy callback
254 // TODO
255 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700256
Junxiao Shid3c792f2014-01-30 00:46:13 -0700257 // foreach pending downstream
258 for (std::set<shared_ptr<Face> >::iterator it = pendingDownstreams.begin();
259 it != pendingDownstreams.end(); ++it) {
260 // goto outgoing Data pipeline
261 this->onOutgoingData(data, **it);
262 }
263}
264
265void
266Forwarder::onDataUnsolicited(Face& inFace, const Data& data)
267{
268 // accept to cache?
269 bool acceptToCache = false;// TODO decision
270 if (acceptToCache) {
271 // CS insert
272 m_cs.insert(data);
273 }
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700274
275 NFD_LOG_DEBUG("onDataUnsolicited face=" << inFace.getId() << " data=" << data.getName() << " acceptToCache=" << acceptToCache);
Junxiao Shid3c792f2014-01-30 00:46:13 -0700276}
277
278void
279Forwarder::onOutgoingData(const Data& data, Face& outFace)
280{
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700281 NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId() << " data=" << data.getName());
282
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700283 // /localhost scope control
284 bool violatesLocalhost = !outFace.isLocal() &&
285 s_localhostName.isPrefixOf(data.getName());
286 if (violatesLocalhost) {
287 NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId()
288 << " data=" << data.getName() << " violates /localhost");
289 return;
290 }
291
Junxiao Shid3c792f2014-01-30 00:46:13 -0700292 // traffic manager
293 // pass through
Junxiao Shic041ca32014-02-25 20:01:15 -0700294
Junxiao Shid3c792f2014-01-30 00:46:13 -0700295 // send Data
296 outFace.sendData(data);
297}
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
Junxiao Shi88884492014-02-15 15:57:43 -0700339void
340Forwarder::dispatchToStrategy(const Face& inFace,
341 const Interest& interest,
342 shared_ptr<fib::Entry> fibEntry,
343 shared_ptr<pit::Entry> pitEntry)
344{
345 m_strategy->afterReceiveInterest(inFace, interest, fibEntry, pitEntry);
346 // TODO dispatch according to fibEntry
347}
Junxiao Shid3c792f2014-01-30 00:46:13 -0700348
Alexander Afanasyev18bbf812014-01-29 01:40:23 -0800349} // namespace nfd