blob: 4c4d3c5f745a217e7bd5b40ce7d7b783bd39117b [file] [log] [blame]
Alexander Afanasyev3ecec502014-04-16 13:42:44 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyev7c10b3b2015-01-20 12:24:27 -08003 * Copyright (c) 2014-2015, Regents of the University of California,
4 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
Alexander Afanasyev3ecec502014-04-16 13:42:44 -070010 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
Vince12e49462014-06-09 13:29:32 -050024 */
Alexander Afanasyev3ecec502014-04-16 13:42:44 -070025
26#include "rib.hpp"
27
Vince Lehman76c751c2014-11-18 17:36:38 -060028#include "fib-updater.hpp"
Vince Lehman281ded72014-08-21 12:17:08 -050029#include "core/logger.hpp"
30
31NFD_LOG_INIT("Rib");
32
Alexander Afanasyev3ecec502014-04-16 13:42:44 -070033namespace nfd {
34namespace rib {
35
Vince Lehman4387e782014-06-19 16:57:45 -050036static inline bool
Vince Lehman218be0a2015-01-15 17:25:20 -060037sortRoutes(const Route& lhs, const Route& rhs)
Vince Lehman4387e782014-06-19 16:57:45 -050038{
Vince Lehman218be0a2015-01-15 17:25:20 -060039 return lhs.faceId < rhs.faceId;
Vince Lehman4387e782014-06-19 16:57:45 -050040}
41
Alexander Afanasyev3ecec502014-04-16 13:42:44 -070042Rib::Rib()
Vince12e49462014-06-09 13:29:32 -050043 : m_nItems(0)
Vince Lehman76c751c2014-11-18 17:36:38 -060044 , m_isUpdateInProgress(false)
Alexander Afanasyev3ecec502014-04-16 13:42:44 -070045{
46}
47
Vince Lehman76c751c2014-11-18 17:36:38 -060048Rib::~Rib()
49{
50}
51
52void
53Rib::setFibUpdater(FibUpdater* updater)
54{
55 m_fibUpdater = updater;
56}
57
Alexander Afanasyev3ecec502014-04-16 13:42:44 -070058Rib::const_iterator
Vince12e49462014-06-09 13:29:32 -050059Rib::find(const Name& prefix) const
Alexander Afanasyev3ecec502014-04-16 13:42:44 -070060{
Vince12e49462014-06-09 13:29:32 -050061 return m_rib.find(prefix);
62}
63
Vince Lehman218be0a2015-01-15 17:25:20 -060064Route*
65Rib::find(const Name& prefix, const Route& route) const
Vince12e49462014-06-09 13:29:32 -050066{
67 RibTable::const_iterator ribIt = m_rib.find(prefix);
68
69 // Name prefix exists
Vince Lehman76c751c2014-11-18 17:36:38 -060070 if (ribIt != m_rib.end()) {
71 shared_ptr<RibEntry> entry = ribIt->second;
Vince12e49462014-06-09 13:29:32 -050072
Vince Lehman76c751c2014-11-18 17:36:38 -060073 RibEntry::iterator routeIt = entry->findRoute(route);
Vince12e49462014-06-09 13:29:32 -050074
Vince Lehman76c751c2014-11-18 17:36:38 -060075 if (routeIt != entry->end()) {
76 return &((*routeIt));
Alexander Afanasyev3ecec502014-04-16 13:42:44 -070077 }
Vince Lehman76c751c2014-11-18 17:36:38 -060078 }
Vince Lehman218be0a2015-01-15 17:25:20 -060079
80 return nullptr;
Alexander Afanasyev3ecec502014-04-16 13:42:44 -070081}
82
Alexander Afanasyev3ecec502014-04-16 13:42:44 -070083void
Vince Lehman218be0a2015-01-15 17:25:20 -060084Rib::insert(const Name& prefix, const Route& route)
Alexander Afanasyev3ecec502014-04-16 13:42:44 -070085{
Vince12e49462014-06-09 13:29:32 -050086 RibTable::iterator ribIt = m_rib.find(prefix);
87
88 // Name prefix exists
Vince Lehman76c751c2014-11-18 17:36:38 -060089 if (ribIt != m_rib.end()) {
90 shared_ptr<RibEntry> entry(ribIt->second);
Vince12e49462014-06-09 13:29:32 -050091
Vince Lehman76c751c2014-11-18 17:36:38 -060092 RibEntry::iterator routeIt = entry->findRoute(route);
Vince12e49462014-06-09 13:29:32 -050093
Vince Lehman76c751c2014-11-18 17:36:38 -060094 if (routeIt == entry->end()) {
95 // New route
Vince Lehman218be0a2015-01-15 17:25:20 -060096 entry->insertRoute(route);
Vince Lehman76c751c2014-11-18 17:36:38 -060097 m_nItems++;
Vince12e49462014-06-09 13:29:32 -050098
99 // Register with face lookup table
Vince Lehman218be0a2015-01-15 17:25:20 -0600100 m_faceMap[route.faceId].push_back(entry);
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700101 }
Vince Lehman76c751c2014-11-18 17:36:38 -0600102 else {
103 // Route exists, update fields
104 // First cancel old scheduled event, if any, then set the EventId to new one
105 if (static_cast<bool>(routeIt->getExpirationEvent())) {
106 NFD_LOG_TRACE("Cancelling expiration event for " << entry->getName() << " "
107 << *routeIt);
108 scheduler::cancel(routeIt->getExpirationEvent());
109 }
110
111 // No checks are required here as the iterator needs to be updated in all cases.
112 routeIt->setExpirationEvent(route.getExpirationEvent());
113
114 routeIt->flags = route.flags;
115 routeIt->cost = route.cost;
116 routeIt->expires = route.expires;
117 }
118 }
119 else {
120 // New name prefix
121 shared_ptr<RibEntry> entry(make_shared<RibEntry>(RibEntry()));
122
123 m_rib[prefix] = entry;
124 m_nItems++;
125
126 entry->setName(prefix);
127 entry->insertRoute(route);
128
129 // Find prefix's parent
130 shared_ptr<RibEntry> parent = findParent(prefix);
131
132 // Add self to parent's children
133 if (parent != nullptr) {
134 parent->addChild(entry);
135 }
136
137 RibEntryList children = findDescendants(prefix);
138
139 for (const auto& child : children) {
140 if (child->getParent() == parent) {
141 // Remove child from parent and inherit parent's child
142 if (parent != nullptr) {
143 parent->removeChild(child);
144 }
145
146 entry->addChild(child);
147 }
148 }
149
150 // Register with face lookup table
151 m_faceMap[route.faceId].push_back(entry);
152
153 // do something after inserting an entry
154 afterInsertEntry(prefix);
155 }
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700156}
157
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700158void
Vince Lehman218be0a2015-01-15 17:25:20 -0600159Rib::erase(const Name& prefix, const Route& route)
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700160{
Vince12e49462014-06-09 13:29:32 -0500161 RibTable::iterator ribIt = m_rib.find(prefix);
162
163 // Name prefix exists
Vince Lehman76c751c2014-11-18 17:36:38 -0600164 if (ribIt != m_rib.end()) {
165 shared_ptr<RibEntry> entry(ribIt->second);
Vince12e49462014-06-09 13:29:32 -0500166
Vince Lehman76c751c2014-11-18 17:36:38 -0600167 RibEntry::iterator routeIt = entry->findRoute(route);
Vince Lehman4387e782014-06-19 16:57:45 -0500168
Vince Lehman76c751c2014-11-18 17:36:38 -0600169 if (routeIt != entry->end()) {
170 entry->eraseRoute(routeIt);
171 m_nItems--;
Vince Lehman4387e782014-06-19 16:57:45 -0500172
Vince Lehman76c751c2014-11-18 17:36:38 -0600173 // If this RibEntry no longer has this faceId, unregister from face lookup table
174 if (!entry->hasFaceId(route.faceId)) {
175 m_faceMap[route.faceId].remove(entry);
176 }
Syed Obaid3313a372014-07-01 01:31:33 -0500177
Vince Lehman76c751c2014-11-18 17:36:38 -0600178 // If a RibEntry's route list is empty, remove it from the tree
179 if (entry->getRoutes().size() == 0) {
180 eraseEntry(ribIt);
181 }
Vince12e49462014-06-09 13:29:32 -0500182 }
Vince Lehman76c751c2014-11-18 17:36:38 -0600183 }
Vince12e49462014-06-09 13:29:32 -0500184}
185
186void
Vince Lehman76c751c2014-11-18 17:36:38 -0600187Rib::onRouteExpiration(const Name& prefix, const Route& route)
Vince12e49462014-06-09 13:29:32 -0500188{
Vince Lehman76c751c2014-11-18 17:36:38 -0600189 NFD_LOG_DEBUG(route << " for " << prefix << " has expired");
Vince12e49462014-06-09 13:29:32 -0500190
Vince Lehman76c751c2014-11-18 17:36:38 -0600191 RibUpdate update;
192 update.setAction(RibUpdate::UNREGISTER)
193 .setName(prefix)
194 .setRoute(route);
Vince12e49462014-06-09 13:29:32 -0500195
Vince Lehman76c751c2014-11-18 17:36:38 -0600196 beginApplyUpdate(update, nullptr, nullptr);
Vince12e49462014-06-09 13:29:32 -0500197}
198
199shared_ptr<RibEntry>
200Rib::findParent(const Name& prefix) const
201{
Vince Lehman76c751c2014-11-18 17:36:38 -0600202 for (int i = prefix.size() - 1; i >= 0; i--) {
203 RibTable::const_iterator it = m_rib.find(prefix.getPrefix(i));
204
205 if (it != m_rib.end()) {
206 return (it->second);
Vince12e49462014-06-09 13:29:32 -0500207 }
Vince Lehman76c751c2014-11-18 17:36:38 -0600208 }
Vince12e49462014-06-09 13:29:32 -0500209
210 return shared_ptr<RibEntry>();
211}
212
213std::list<shared_ptr<RibEntry> >
214Rib::findDescendants(const Name& prefix) const
215{
216 std::list<shared_ptr<RibEntry> > children;
217
218 RibTable::const_iterator it = m_rib.find(prefix);
219
Vince Lehman76c751c2014-11-18 17:36:38 -0600220 if (it != m_rib.end()) {
221 ++it;
222 for (; it != m_rib.end(); ++it) {
223 if (prefix.isPrefixOf(it->first)) {
224 children.push_back((it->second));
225 }
226 else {
227 break;
228 }
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700229 }
Vince Lehman76c751c2014-11-18 17:36:38 -0600230 }
231
232 return children;
233}
234
235std::list<shared_ptr<RibEntry>>
236Rib::findDescendantsForNonInsertedName(const Name& prefix) const
237{
238 std::list<shared_ptr<RibEntry>> children;
239
240 for (std::pair<Name, shared_ptr<RibEntry>> pair : m_rib) {
241 if (prefix.isPrefixOf(pair.first)) {
242 children.push_back(pair.second);
243 }
244 }
Vince12e49462014-06-09 13:29:32 -0500245
246 return children;
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700247}
248
Vince12e49462014-06-09 13:29:32 -0500249Rib::RibTable::iterator
250Rib::eraseEntry(RibTable::iterator it)
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700251{
Vince12e49462014-06-09 13:29:32 -0500252 // Entry does not exist
Vince Lehman76c751c2014-11-18 17:36:38 -0600253 if (it == m_rib.end()) {
254 return m_rib.end();
255 }
Vince12e49462014-06-09 13:29:32 -0500256
257 shared_ptr<RibEntry> entry(it->second);
258
259 shared_ptr<RibEntry> parent = entry->getParent();
260
261 // Remove self from parent's children
Vince Lehman76c751c2014-11-18 17:36:38 -0600262 if (parent != nullptr) {
263 parent->removeChild(entry);
264 }
265
266 for (auto childIt = entry->getChildren().begin(); childIt != entry->getChildren().end(); ) {
267 shared_ptr<RibEntry> child = *childIt;
268
269 // Advance iterator so it is not invalidated by removal
270 ++childIt;
271
272 // Remove children from self
273 entry->removeChild(child);
274
275 // Update parent's children
276 if (parent != nullptr) {
277 parent->addChild(child);
Vince12e49462014-06-09 13:29:32 -0500278 }
Vince Lehman76c751c2014-11-18 17:36:38 -0600279 }
Vince12e49462014-06-09 13:29:32 -0500280
Vince Lehman76c751c2014-11-18 17:36:38 -0600281 RibTable::iterator nextIt = m_rib.erase(it);
Vince12e49462014-06-09 13:29:32 -0500282
Yanbiao Lic17de832014-11-21 17:51:45 -0800283 // do something after erasing an entry.
284 afterEraseEntry(entry->getName());
285
Vince12e49462014-06-09 13:29:32 -0500286 return nextIt;
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700287}
288
Vince Lehman218be0a2015-01-15 17:25:20 -0600289Rib::RouteSet
290Rib::getAncestorRoutes(const RibEntry& entry) const
Vince Lehman4387e782014-06-19 16:57:45 -0500291{
Vince Lehman218be0a2015-01-15 17:25:20 -0600292 RouteSet ancestorRoutes(&sortRoutes);
Vince Lehman4387e782014-06-19 16:57:45 -0500293
294 shared_ptr<RibEntry> parent = entry.getParent();
295
Vince Lehman76c751c2014-11-18 17:36:38 -0600296 while (parent != nullptr) {
297 for (const Route& route : parent->getRoutes()) {
298 if (route.isChildInherit()) {
299 ancestorRoutes.insert(route);
Vince Lehman4387e782014-06-19 16:57:45 -0500300 }
Vince Lehman4387e782014-06-19 16:57:45 -0500301 }
302
Vince Lehman76c751c2014-11-18 17:36:38 -0600303 if (parent->hasCapture()) {
304 break;
Vince Lehman4387e782014-06-19 16:57:45 -0500305 }
Vince Lehman76c751c2014-11-18 17:36:38 -0600306
307 parent = parent->getParent();
308 }
309
310 return ancestorRoutes;
311}
312
313Rib::RouteSet
314Rib::getAncestorRoutes(const Name& name) const
315{
316 RouteSet ancestorRoutes(&sortRoutes);
317
318 shared_ptr<RibEntry> parent = findParent(name);
319
320 while (parent != nullptr) {
321 for (const Route& route : parent->getRoutes()) {
322 if (route.isChildInherit()) {
323 ancestorRoutes.insert(route);
324 }
325 }
326
327 if (parent->hasCapture()) {
328 break;
329 }
330
331 parent = parent->getParent();
332 }
333
334 return ancestorRoutes;
335}
336
337void
338Rib::beginApplyUpdate(const RibUpdate& update,
339 const Rib::UpdateSuccessCallback& onSuccess,
340 const Rib::UpdateFailureCallback& onFailure)
341{
342 BOOST_ASSERT(m_fibUpdater != nullptr);
343
344 addUpdateToQueue(update, onSuccess, onFailure);
345
346 sendBatchFromQueue();
347}
348
349void
350Rib::beginRemoveFace(uint64_t faceId)
351{
352 for (const auto& nameAndRoute : findRoutesWithFaceId(faceId)) {
353 RibUpdate update;
354 update.setAction(RibUpdate::REMOVE_FACE)
355 .setName(nameAndRoute.first)
356 .setRoute(nameAndRoute.second);
357
358 addUpdateToQueue(update, nullptr, nullptr);
359 }
360
361 sendBatchFromQueue();
362}
363
364void
365Rib::addUpdateToQueue(const RibUpdate& update,
366 const Rib::UpdateSuccessCallback& onSuccess,
367 const Rib::UpdateFailureCallback& onFailure)
368{
369 RibUpdateBatch batch(update.getRoute().faceId);
370 batch.add(update);
371
372 UpdateQueueItem item{batch, onSuccess, onFailure};
373 m_updateBatches.push_back(std::move(item));
374}
375
376void
377Rib::sendBatchFromQueue()
378{
379 if (m_updateBatches.empty() || m_isUpdateInProgress) {
380 return;
381 }
382
383 m_isUpdateInProgress = true;
384
385 UpdateQueueItem item = std::move(m_updateBatches.front());
386 m_updateBatches.pop_front();
387
388 RibUpdateBatch& batch = item.batch;
389
390 // Until task #1698, each RibUpdateBatch contains exactly one RIB update
391 BOOST_ASSERT(batch.size() == 1);
392
393 const Rib::UpdateSuccessCallback& managerSuccessCallback = item.managerSuccessCallback;
394 const Rib::UpdateFailureCallback& managerFailureCallback = item.managerFailureCallback;
395
396 m_fibUpdater->computeAndSendFibUpdates(batch,
397 bind(&Rib::onFibUpdateSuccess, this,
398 batch, _1, managerSuccessCallback),
399 bind(&Rib::onFibUpdateFailure, this,
400 managerFailureCallback, _1, _2));
401
402 if (m_onSendBatchFromQueue != nullptr) {
403 m_onSendBatchFromQueue(batch);
404 }
405}
406
407void
408Rib::onFibUpdateSuccess(const RibUpdateBatch& batch,
409 const RibUpdateList& inheritedRoutes,
410 const Rib::UpdateSuccessCallback& onSuccess)
411{
412 for (const RibUpdate& update : batch) {
413 switch (update.getAction()) {
414 case RibUpdate::REGISTER:
415 insert(update.getName(), update.getRoute());
416 break;
417 case RibUpdate::UNREGISTER:
418 case RibUpdate::REMOVE_FACE:
419 erase(update.getName(), update.getRoute());
420 break;
421 }
422 }
423
424 // Add and remove precalculated inherited routes to RibEntries
425 modifyInheritedRoutes(inheritedRoutes);
426
427 m_isUpdateInProgress = false;
428
429 if (onSuccess != nullptr) {
430 onSuccess();
431 }
432
433 // Try to advance the batch queue
434 sendBatchFromQueue();
435}
436
437void
438Rib::onFibUpdateFailure(const Rib::UpdateFailureCallback& onFailure,
439 uint32_t code, const std::string& error)
440{
441 m_isUpdateInProgress = false;
442
443 if (onFailure != nullptr) {
444 onFailure(code, error);
445 }
446
447 // Try to advance the batch queue
448 sendBatchFromQueue();
449}
450
451void
452Rib::modifyInheritedRoutes(const RibUpdateList& inheritedRoutes)
453{
454 for (const RibUpdate& update : inheritedRoutes) {
455 RibTable::iterator ribIt = m_rib.find(update.getName());
456
457 BOOST_ASSERT(ribIt != m_rib.end());
458 shared_ptr<RibEntry> entry(ribIt->second);
459
460 switch (update.getAction()) {
461 case RibUpdate::REGISTER:
462 entry->addInheritedRoute(update.getRoute());
463 break;
464 case RibUpdate::UNREGISTER:
465 entry->removeInheritedRoute(update.getRoute());
466 break;
467 case RibUpdate::REMOVE_FACE:
468 break;
469 }
470 }
471}
472
473std::list<Rib::NameAndRoute>
474Rib::findRoutesWithFaceId(uint64_t faceId)
475{
476 std::list<NameAndRoute> routes;
477
478 FaceLookupTable::iterator lookupIt = m_faceMap.find(faceId);
479
480 // No RIB entries have this face
481 if (lookupIt == m_faceMap.end()) {
482 return routes;
483 }
484
485 RibEntryList& ribEntries = lookupIt->second;
486
487 // For each RIB entry that has faceId
488 for (const shared_ptr<RibEntry>& entry : ribEntries) {
489 // Find the routes in the entry
490 for (const Route& route : *entry) {
491 if (route.faceId == faceId) {
492 routes.push_back(NameAndRoute(entry->getName(), route));
493 }
494 }
495 }
496
497 return routes;
Vince Lehman4387e782014-06-19 16:57:45 -0500498}
499
Alexander Afanasyev20d31442014-04-19 17:00:53 -0700500std::ostream&
Vince12e49462014-06-09 13:29:32 -0500501operator<<(std::ostream& os, const Rib& rib)
Alexander Afanasyev20d31442014-04-19 17:00:53 -0700502{
Vince Lehman76c751c2014-11-18 17:36:38 -0600503 for (const auto& item : rib) {
504 os << item.second << "\n";
505 }
Alexander Afanasyev20d31442014-04-19 17:00:53 -0700506
507 return os;
508}
509
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700510} // namespace rib
511} // namespace nfd