blob: a8121980e9d7d91093328b02a8e74fe6445a6972 [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
Junxiao Shi40631842014-03-01 13:52:37 -070093 shared_ptr<pit::Entry> pitEntry = m_pit.insert(interest).first;
Junxiao Shic041ca32014-02-25 20:01:15 -070094
Junxiao Shid3c792f2014-01-30 00:46:13 -070095 // detect loop and record Nonce
96 bool isLoop = ! pitEntry->addNonce(interest.getNonce());
97 if (isLoop) {
98 // goto Interest loop pipeline
99 this->onInterestLoop(inFace, interest, pitEntry);
100 return;
101 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700102
Junxiao Shid3c792f2014-01-30 00:46:13 -0700103 // cancel unsatisfy & straggler timer
104 this->cancelUnsatisfyAndStragglerTimer(pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -0700105
Junxiao Shid3c792f2014-01-30 00:46:13 -0700106 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
107 bool isPending = inRecords.begin() == inRecords.end();
Junxiao Shic041ca32014-02-25 20:01:15 -0700108
Junxiao Shid3c792f2014-01-30 00:46:13 -0700109 if (!isPending) {
110 // CS lookup
111 const Data* csMatch = m_cs.find(interest);
112 if (csMatch != 0) {
113 // XXX should we lookup PIT for other Interests that also match csMatch?
114
115 // goto outgoing Data pipeline
116 this->onOutgoingData(*csMatch, inFace);
117 return;
118 }
119 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700120
Junxiao Shid3c792f2014-01-30 00:46:13 -0700121 // insert InRecord
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700122 pitEntry->insertOrUpdateInRecord(inFace.shared_from_this(), interest);
Junxiao Shic041ca32014-02-25 20:01:15 -0700123
Junxiao Shid3c792f2014-01-30 00:46:13 -0700124 // app chosen nexthops
125 bool isAppChosenNexthops = false; // TODO get from local control header
126 if (isAppChosenNexthops) {
127 // TODO foreach chosen nexthop: goto outgoing Interest pipeline
128 return;
129 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700130
Junxiao Shid3c792f2014-01-30 00:46:13 -0700131 // FIB lookup
Junxiao Shi40631842014-03-01 13:52:37 -0700132 shared_ptr<fib::Entry> fibEntry = m_fib.findLongestPrefixMatch(*pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -0700133
Junxiao Shid3c792f2014-01-30 00:46:13 -0700134 // dispatch to strategy
Junxiao Shi88884492014-02-15 15:57:43 -0700135 this->dispatchToStrategy(inFace, interest, fibEntry, pitEntry);
Junxiao Shid3c792f2014-01-30 00:46:13 -0700136}
137
138void
139Forwarder::onInterestLoop(Face& inFace, const Interest& interest,
140 shared_ptr<pit::Entry> pitEntry)
141{
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700142 NFD_LOG_DEBUG("onInterestLoop face=" << inFace.getId() << " interest=" << interest.getName());
143
Junxiao Shid3c792f2014-01-30 00:46:13 -0700144 // do nothing, which means Interest is dropped
145}
146
147void
148Forwarder::onOutgoingInterest(shared_ptr<pit::Entry> pitEntry, Face& outFace)
149{
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700150 NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() << " interest=" << pitEntry->getName());
151
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700152 // /localhost scope control
153 bool violatesLocalhost = !outFace.isLocal() &&
154 s_localhostName.isPrefixOf(pitEntry->getName());
155 if (violatesLocalhost) {
156 NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId()
157 << " interest=" << pitEntry->getName() << " violates /localhost");
158 return;
159 }
160
Junxiao Shid3c792f2014-01-30 00:46:13 -0700161 // pick Interest
162 const Interest& interest = pitEntry->getInterest();
163 // TODO pick the last incoming Interest
Junxiao Shic041ca32014-02-25 20:01:15 -0700164
Junxiao Shid3c792f2014-01-30 00:46:13 -0700165 // insert OutRecord
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700166 pitEntry->insertOrUpdateOutRecord(outFace.shared_from_this(), interest);
Junxiao Shic041ca32014-02-25 20:01:15 -0700167
Junxiao Shid3c792f2014-01-30 00:46:13 -0700168 // set PIT unsatisfy timer
169 this->setUnsatisfyTimer(pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -0700170
Junxiao Shid3c792f2014-01-30 00:46:13 -0700171 // send Interest
172 outFace.sendInterest(interest);
173}
174
175void
Junxiao Shi09498f02014-02-26 19:41:08 -0700176Forwarder::onInterestReject(shared_ptr<pit::Entry> pitEntry)
Junxiao Shid3c792f2014-01-30 00:46:13 -0700177{
Junxiao Shi09498f02014-02-26 19:41:08 -0700178 NFD_LOG_DEBUG("onInterestReject interest=" << pitEntry->getName());
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700179
Junxiao Shid3c792f2014-01-30 00:46:13 -0700180 // set PIT straggler timer
181 this->setStragglerTimer(pitEntry);
182}
183
184void
185Forwarder::onInterestUnsatisfied(shared_ptr<pit::Entry> pitEntry)
186{
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700187 NFD_LOG_DEBUG("onInterestUnsatisfied interest=" << pitEntry->getName());
188
Junxiao Shid3c792f2014-01-30 00:46:13 -0700189 // invoke PIT unsatisfied callback
190 // TODO
Junxiao Shic041ca32014-02-25 20:01:15 -0700191
Haowei Yuan78c84d12014-02-27 15:35:13 -0600192 // PIT erase
193 m_pit.erase(pitEntry);
Junxiao Shid3c792f2014-01-30 00:46:13 -0700194}
195
196void
197Forwarder::onIncomingData(Face& inFace, const Data& data)
198{
199 // receive Data
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700200 NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId() << " data=" << data.getName());
Junxiao Shi06887ac2014-02-13 20:15:42 -0700201 const_cast<Data&>(data).setIncomingFaceId(inFace.getId());
Junxiao Shic041ca32014-02-25 20:01:15 -0700202
Junxiao Shi88884492014-02-15 15:57:43 -0700203 // /localhost scope control
204 bool violatesLocalhost = !inFace.isLocal() &&
205 s_localhostName.isPrefixOf(data.getName());
206 if (violatesLocalhost) {
207 NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId()
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700208 << " data=" << data.getName() << " violates /localhost");
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
250 // TODO
251 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700252
Junxiao Shid3c792f2014-01-30 00:46:13 -0700253 // foreach pending downstream
254 for (std::set<shared_ptr<Face> >::iterator it = pendingDownstreams.begin();
255 it != pendingDownstreams.end(); ++it) {
256 // goto outgoing Data pipeline
257 this->onOutgoingData(data, **it);
258 }
259}
260
261void
262Forwarder::onDataUnsolicited(Face& inFace, const Data& data)
263{
264 // accept to cache?
265 bool acceptToCache = false;// TODO decision
266 if (acceptToCache) {
267 // CS insert
268 m_cs.insert(data);
269 }
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700270
271 NFD_LOG_DEBUG("onDataUnsolicited face=" << inFace.getId() << " data=" << data.getName() << " acceptToCache=" << acceptToCache);
Junxiao Shid3c792f2014-01-30 00:46:13 -0700272}
273
274void
275Forwarder::onOutgoingData(const Data& data, Face& outFace)
276{
Junxiao Shi8c8d2182014-01-30 22:33:00 -0700277 NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId() << " data=" << data.getName());
278
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700279 // /localhost scope control
280 bool violatesLocalhost = !outFace.isLocal() &&
281 s_localhostName.isPrefixOf(data.getName());
282 if (violatesLocalhost) {
283 NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId()
284 << " data=" << data.getName() << " violates /localhost");
285 return;
286 }
287
Junxiao Shid3c792f2014-01-30 00:46:13 -0700288 // traffic manager
289 // pass through
Junxiao Shic041ca32014-02-25 20:01:15 -0700290
Junxiao Shid3c792f2014-01-30 00:46:13 -0700291 // send Data
292 outFace.sendData(data);
293}
294
295static inline bool
296compare_InRecord_expiry(const pit::InRecord& a, const pit::InRecord& b)
297{
298 return a.getExpiry() < b.getExpiry();
299}
300
301void
302Forwarder::setUnsatisfyTimer(shared_ptr<pit::Entry> pitEntry)
303{
304 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
305 pit::InRecordCollection::const_iterator lastExpiring =
306 std::max_element(inRecords.begin(), inRecords.end(),
307 &compare_InRecord_expiry);
308
309 time::Point lastExpiry = lastExpiring->getExpiry();
310 time::Duration lastExpiryFromNow = lastExpiry - time::now();
311 if (lastExpiryFromNow <= time::seconds(0)) {
312 // TODO all InRecords are already expired; will this happen?
313 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700314
315 pitEntry->m_unsatisfyTimer = scheduler::schedule(lastExpiryFromNow,
Junxiao Shid3c792f2014-01-30 00:46:13 -0700316 bind(&Forwarder::onInterestUnsatisfied, this, pitEntry));
317}
318
319void
320Forwarder::setStragglerTimer(shared_ptr<pit::Entry> pitEntry)
321{
322 time::Duration stragglerTime = time::milliseconds(100);
Junxiao Shic041ca32014-02-25 20:01:15 -0700323
324 pitEntry->m_stragglerTimer = scheduler::schedule(stragglerTime,
Haowei Yuan78c84d12014-02-27 15:35:13 -0600325 bind(&Pit::erase, &m_pit, pitEntry));
Junxiao Shid3c792f2014-01-30 00:46:13 -0700326}
327
328void
329Forwarder::cancelUnsatisfyAndStragglerTimer(shared_ptr<pit::Entry> pitEntry)
330{
Junxiao Shic041ca32014-02-25 20:01:15 -0700331 scheduler::cancel(pitEntry->m_unsatisfyTimer);
332 scheduler::cancel(pitEntry->m_stragglerTimer);
Junxiao Shid3c792f2014-01-30 00:46:13 -0700333}
334
Junxiao Shi88884492014-02-15 15:57:43 -0700335void
336Forwarder::dispatchToStrategy(const Face& inFace,
337 const Interest& interest,
338 shared_ptr<fib::Entry> fibEntry,
339 shared_ptr<pit::Entry> pitEntry)
340{
341 m_strategy->afterReceiveInterest(inFace, interest, fibEntry, pitEntry);
342 // TODO dispatch according to fibEntry
343}
Junxiao Shid3c792f2014-01-30 00:46:13 -0700344
Alexander Afanasyev18bbf812014-01-29 01:40:23 -0800345} // namespace nfd