blob: a605ef0ddc5a37cbfda4c31b096aa9df75a1682f [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)
Alexander Afanasyev33b72772014-01-26 23:22:58 -080019{
Junxiao Shi8c8d2182014-01-30 22:33:00 -070020 m_strategy = make_shared<fw::BestRouteStrategy>(boost::ref(*this));
Alexander Afanasyev33b72772014-01-26 23:22:58 -080021}
22
23void
Junxiao Shi8c8d2182014-01-30 22:33:00 -070024Forwarder::addFace(shared_ptr<Face> face)
Alexander Afanasyev33b72772014-01-26 23:22:58 -080025{
Junxiao Shi8c8d2182014-01-30 22:33:00 -070026 FaceId faceId = ++m_lastFaceId;
27 face->setId(faceId);
28 m_faces[faceId] = face;
29 NFD_LOG_INFO("addFace id=" << faceId);
30
31 face->onReceiveInterest += bind(&Forwarder::onInterest,
32 this, boost::ref(*face), _1);
33 face->onReceiveData += bind(&Forwarder::onData,
34 this, boost::ref(*face), _1);
Alexander Afanasyev33b72772014-01-26 23:22:58 -080035}
36
37void
Junxiao Shi8c8d2182014-01-30 22:33:00 -070038Forwarder::removeFace(shared_ptr<Face> face)
Alexander Afanasyev33b72772014-01-26 23:22:58 -080039{
Junxiao Shi8c8d2182014-01-30 22:33:00 -070040 FaceId faceId = face->getId();
41 m_faces.erase(faceId);
42 face->setId(INVALID_FACEID);
43 NFD_LOG_INFO("removeFace id=" << faceId);
Junxiao Shic041ca32014-02-25 20:01:15 -070044
Junxiao Shi8c8d2182014-01-30 22:33:00 -070045 // XXX This clears all subscriptions, because EventEmitter
46 // does not support only removing Forwarder's subscription
47 face->onReceiveInterest.clear();
48 face->onReceiveData .clear();
Junxiao Shic041ca32014-02-25 20:01:15 -070049
Junxiao Shi8c8d2182014-01-30 22:33:00 -070050 m_fib.removeNextHopFromAllEntries(face);
Alexander Afanasyev33b72772014-01-26 23:22:58 -080051}
52
Steve DiBenedetto26b730f2014-02-02 18:36:16 -070053shared_ptr<Face>
54Forwarder::getFace(FaceId id)
55{
56 std::map<FaceId, shared_ptr<Face> >::iterator i = m_faces.find(id);
57 return (i == m_faces.end()) ? (shared_ptr<Face>()) : (i->second);
58}
59
Alexander Afanasyev33b72772014-01-26 23:22:58 -080060void
Junxiao Shi8c8d2182014-01-30 22:33:00 -070061Forwarder::onInterest(Face& face, const Interest& interest)
Alexander Afanasyev33b72772014-01-26 23:22:58 -080062{
Junxiao Shi8c8d2182014-01-30 22:33:00 -070063 this->onIncomingInterest(face, interest);
64}
65
66void
67Forwarder::onData(Face& face, const Data& data)
68{
69 this->onIncomingData(face, data);
Alexander Afanasyev33b72772014-01-26 23:22:58 -080070}
71
Junxiao Shid3c792f2014-01-30 00:46:13 -070072void
73Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
74{
75 // receive Interest
Junxiao Shi8c8d2182014-01-30 22:33:00 -070076 NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() << " interest=" << interest.getName());
Junxiao Shi06887ac2014-02-13 20:15:42 -070077 const_cast<Interest&>(interest).setIncomingFaceId(inFace.getId());
Junxiao Shic041ca32014-02-25 20:01:15 -070078
Junxiao Shi88884492014-02-15 15:57:43 -070079 // /localhost scope control
80 bool violatesLocalhost = !inFace.isLocal() &&
81 s_localhostName.isPrefixOf(interest.getName());
82 if (violatesLocalhost) {
83 NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId()
84 << " interest=" << interest.getName() << " violates /localhost");
85 return;
86 }
Junxiao Shic041ca32014-02-25 20:01:15 -070087
Junxiao Shid3c792f2014-01-30 00:46:13 -070088 // PIT insert
89 std::pair<shared_ptr<pit::Entry>, bool>
90 pitInsertResult = m_pit.insert(interest);
91 shared_ptr<pit::Entry> pitEntry = pitInsertResult.first;
Junxiao Shic041ca32014-02-25 20:01:15 -070092
Junxiao Shid3c792f2014-01-30 00:46:13 -070093 // detect loop and record Nonce
94 bool isLoop = ! pitEntry->addNonce(interest.getNonce());
95 if (isLoop) {
96 // goto Interest loop pipeline
97 this->onInterestLoop(inFace, interest, pitEntry);
98 return;
99 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700100
Junxiao Shid3c792f2014-01-30 00:46:13 -0700101 // cancel unsatisfy & straggler timer
102 this->cancelUnsatisfyAndStragglerTimer(pitEntry);
Junxiao Shic041ca32014-02-25 20:01:15 -0700103
Junxiao Shid3c792f2014-01-30 00:46:13 -0700104 const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
105 bool isPending = inRecords.begin() == inRecords.end();
Junxiao Shic041ca32014-02-25 20:01:15 -0700106
Junxiao Shid3c792f2014-01-30 00:46:13 -0700107 if (!isPending) {
108 // CS lookup
109 const Data* csMatch = m_cs.find(interest);
110 if (csMatch != 0) {
111 // XXX should we lookup PIT for other Interests that also match csMatch?
112
113 // goto outgoing Data pipeline
114 this->onOutgoingData(*csMatch, inFace);
115 return;
116 }
117 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700118
Junxiao Shid3c792f2014-01-30 00:46:13 -0700119 // insert InRecord
Junxiao Shi9b27bd22014-02-26 20:29:58 -0700120 pitEntry->insertOrUpdateInRecord(inFace.shared_from_this(), interest);
Junxiao Shic041ca32014-02-25 20:01:15 -0700121
Junxiao Shid3c792f2014-01-30 00:46:13 -0700122 // app chosen nexthops
123 bool isAppChosenNexthops = false; // TODO get from local control header
124 if (isAppChosenNexthops) {
125 // TODO foreach chosen nexthop: goto outgoing Interest pipeline
126 return;
127 }
Junxiao Shic041ca32014-02-25 20:01:15 -0700128
Junxiao Shid3c792f2014-01-30 00:46:13 -0700129 // FIB lookup
130 shared_ptr<fib::Entry> fibEntry
131 = m_fib.findLongestPrefixMatch(interest.getName());
132 // TODO use Fib::findParent(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
Junxiao Shid3c792f2014-01-30 00:46:13 -0700192 // PIT delete
193 m_pit.remove(pitEntry);
194}
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,
Junxiao Shid3c792f2014-01-30 00:46:13 -0700325 bind(&Pit::remove, &m_pit, pitEntry));
326}
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