blob: 97492b28d32695ff73ee2f9f49d193b1ef582385 [file] [log] [blame]
Alexander Afanasyev3ecec502014-04-16 13:42:44 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Davide Pesaventoe94804b2016-09-19 17:23:21 +00003 * Copyright (c) 2014-2016, Regents of the University of California,
Alexander Afanasyev7c10b3b2015-01-20 12:24:27 -08004 * 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
Nick Gordon89c4cca2016-11-02 15:42:32 +000092 RibEntry::iterator entryIt;
93 bool didInsert = false;
94 std::tie(entryIt, didInsert) = entry->insertRoute(route);
Vince12e49462014-06-09 13:29:32 -050095
Nick Gordon89c4cca2016-11-02 15:42:32 +000096 if (didInsert) {
97 // The route was new and we successfully inserted it.
Vince Lehman76c751c2014-11-18 17:36:38 -060098 m_nItems++;
Vince12e49462014-06-09 13:29:32 -050099
Nick Gordon89c4cca2016-11-02 15:42:32 +0000100 afterAddRoute(RibRouteRef{entry, entryIt});
101
Vince12e49462014-06-09 13:29:32 -0500102 // Register with face lookup table
Vince Lehman218be0a2015-01-15 17:25:20 -0600103 m_faceMap[route.faceId].push_back(entry);
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700104 }
Vince Lehman76c751c2014-11-18 17:36:38 -0600105 else {
106 // Route exists, update fields
107 // First cancel old scheduled event, if any, then set the EventId to new one
Nick Gordon89c4cca2016-11-02 15:42:32 +0000108 if (static_cast<bool>(entryIt->getExpirationEvent())) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600109 NFD_LOG_TRACE("Cancelling expiration event for " << entry->getName() << " "
Nick Gordon89c4cca2016-11-02 15:42:32 +0000110 << (*entryIt));
111 scheduler::cancel(entryIt->getExpirationEvent());
Vince Lehman76c751c2014-11-18 17:36:38 -0600112 }
113
114 // No checks are required here as the iterator needs to be updated in all cases.
Nick Gordon89c4cca2016-11-02 15:42:32 +0000115 entryIt->setExpirationEvent(route.getExpirationEvent());
Vince Lehman76c751c2014-11-18 17:36:38 -0600116
Nick Gordon89c4cca2016-11-02 15:42:32 +0000117 entryIt->flags = route.flags;
118 entryIt->cost = route.cost;
119 entryIt->expires = route.expires;
Vince Lehman76c751c2014-11-18 17:36:38 -0600120 }
121 }
122 else {
123 // New name prefix
Nick Gordon89c4cca2016-11-02 15:42:32 +0000124 shared_ptr<RibEntry> entry = make_shared<RibEntry>();
Vince Lehman76c751c2014-11-18 17:36:38 -0600125
126 m_rib[prefix] = entry;
127 m_nItems++;
128
129 entry->setName(prefix);
Nick Gordon89c4cca2016-11-02 15:42:32 +0000130 RibEntry::iterator routeIt = entry->insertRoute(route).first;
Vince Lehman76c751c2014-11-18 17:36:38 -0600131
132 // Find prefix's parent
133 shared_ptr<RibEntry> parent = findParent(prefix);
134
135 // Add self to parent's children
136 if (parent != nullptr) {
137 parent->addChild(entry);
138 }
139
140 RibEntryList children = findDescendants(prefix);
141
142 for (const auto& child : children) {
143 if (child->getParent() == parent) {
144 // Remove child from parent and inherit parent's child
145 if (parent != nullptr) {
146 parent->removeChild(child);
147 }
148
149 entry->addChild(child);
150 }
151 }
152
153 // Register with face lookup table
154 m_faceMap[route.faceId].push_back(entry);
155
156 // do something after inserting an entry
157 afterInsertEntry(prefix);
Nick Gordon89c4cca2016-11-02 15:42:32 +0000158 afterAddRoute(RibRouteRef{entry, routeIt});
Vince Lehman76c751c2014-11-18 17:36:38 -0600159 }
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700160}
161
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700162void
Vince Lehman218be0a2015-01-15 17:25:20 -0600163Rib::erase(const Name& prefix, const Route& route)
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700164{
Vince12e49462014-06-09 13:29:32 -0500165 RibTable::iterator ribIt = m_rib.find(prefix);
166
167 // Name prefix exists
Vince Lehman76c751c2014-11-18 17:36:38 -0600168 if (ribIt != m_rib.end()) {
Davide Pesaventoe94804b2016-09-19 17:23:21 +0000169 shared_ptr<RibEntry> entry = ribIt->second;
Vince Lehman76c751c2014-11-18 17:36:38 -0600170 RibEntry::iterator routeIt = entry->findRoute(route);
Vince Lehman4387e782014-06-19 16:57:45 -0500171
Vince Lehman76c751c2014-11-18 17:36:38 -0600172 if (routeIt != entry->end()) {
Nick Gordon89c4cca2016-11-02 15:42:32 +0000173 beforeRemoveRoute(RibRouteRef{entry, routeIt});
174
Davide Pesaventoe94804b2016-09-19 17:23:21 +0000175 auto faceId = route.faceId;
Vince Lehman76c751c2014-11-18 17:36:38 -0600176 entry->eraseRoute(routeIt);
177 m_nItems--;
Vince Lehman4387e782014-06-19 16:57:45 -0500178
Vince Lehman76c751c2014-11-18 17:36:38 -0600179 // If this RibEntry no longer has this faceId, unregister from face lookup table
Davide Pesaventoe94804b2016-09-19 17:23:21 +0000180 if (!entry->hasFaceId(faceId)) {
181 m_faceMap[faceId].remove(entry);
Vince Lehman76c751c2014-11-18 17:36:38 -0600182 }
Syed Obaid3313a372014-07-01 01:31:33 -0500183
Vince Lehman76c751c2014-11-18 17:36:38 -0600184 // If a RibEntry's route list is empty, remove it from the tree
Davide Pesaventoe94804b2016-09-19 17:23:21 +0000185 if (entry->getRoutes().empty()) {
Vince Lehman76c751c2014-11-18 17:36:38 -0600186 eraseEntry(ribIt);
187 }
Vince12e49462014-06-09 13:29:32 -0500188 }
Vince Lehman76c751c2014-11-18 17:36:38 -0600189 }
Vince12e49462014-06-09 13:29:32 -0500190}
191
192void
Vince Lehman76c751c2014-11-18 17:36:38 -0600193Rib::onRouteExpiration(const Name& prefix, const Route& route)
Vince12e49462014-06-09 13:29:32 -0500194{
Vince Lehman76c751c2014-11-18 17:36:38 -0600195 NFD_LOG_DEBUG(route << " for " << prefix << " has expired");
Vince12e49462014-06-09 13:29:32 -0500196
Vince Lehman76c751c2014-11-18 17:36:38 -0600197 RibUpdate update;
198 update.setAction(RibUpdate::UNREGISTER)
199 .setName(prefix)
200 .setRoute(route);
Vince12e49462014-06-09 13:29:32 -0500201
Vince Lehman76c751c2014-11-18 17:36:38 -0600202 beginApplyUpdate(update, nullptr, nullptr);
Vince12e49462014-06-09 13:29:32 -0500203}
204
205shared_ptr<RibEntry>
206Rib::findParent(const Name& prefix) const
207{
Vince Lehman76c751c2014-11-18 17:36:38 -0600208 for (int i = prefix.size() - 1; i >= 0; i--) {
209 RibTable::const_iterator it = m_rib.find(prefix.getPrefix(i));
210
211 if (it != m_rib.end()) {
212 return (it->second);
Vince12e49462014-06-09 13:29:32 -0500213 }
Vince Lehman76c751c2014-11-18 17:36:38 -0600214 }
Vince12e49462014-06-09 13:29:32 -0500215
216 return shared_ptr<RibEntry>();
217}
218
219std::list<shared_ptr<RibEntry> >
220Rib::findDescendants(const Name& prefix) const
221{
222 std::list<shared_ptr<RibEntry> > children;
223
224 RibTable::const_iterator it = m_rib.find(prefix);
225
Vince Lehman76c751c2014-11-18 17:36:38 -0600226 if (it != m_rib.end()) {
227 ++it;
228 for (; it != m_rib.end(); ++it) {
229 if (prefix.isPrefixOf(it->first)) {
230 children.push_back((it->second));
231 }
232 else {
233 break;
234 }
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700235 }
Vince Lehman76c751c2014-11-18 17:36:38 -0600236 }
237
238 return children;
239}
240
241std::list<shared_ptr<RibEntry>>
242Rib::findDescendantsForNonInsertedName(const Name& prefix) const
243{
244 std::list<shared_ptr<RibEntry>> children;
245
246 for (std::pair<Name, shared_ptr<RibEntry>> pair : m_rib) {
247 if (prefix.isPrefixOf(pair.first)) {
248 children.push_back(pair.second);
249 }
250 }
Vince12e49462014-06-09 13:29:32 -0500251
252 return children;
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700253}
254
Vince12e49462014-06-09 13:29:32 -0500255Rib::RibTable::iterator
256Rib::eraseEntry(RibTable::iterator it)
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700257{
Vince12e49462014-06-09 13:29:32 -0500258 // Entry does not exist
Vince Lehman76c751c2014-11-18 17:36:38 -0600259 if (it == m_rib.end()) {
260 return m_rib.end();
261 }
Vince12e49462014-06-09 13:29:32 -0500262
263 shared_ptr<RibEntry> entry(it->second);
264
265 shared_ptr<RibEntry> parent = entry->getParent();
266
267 // Remove self from parent's children
Vince Lehman76c751c2014-11-18 17:36:38 -0600268 if (parent != nullptr) {
269 parent->removeChild(entry);
270 }
271
272 for (auto childIt = entry->getChildren().begin(); childIt != entry->getChildren().end(); ) {
273 shared_ptr<RibEntry> child = *childIt;
274
275 // Advance iterator so it is not invalidated by removal
276 ++childIt;
277
278 // Remove children from self
279 entry->removeChild(child);
280
281 // Update parent's children
282 if (parent != nullptr) {
283 parent->addChild(child);
Vince12e49462014-06-09 13:29:32 -0500284 }
Vince Lehman76c751c2014-11-18 17:36:38 -0600285 }
Vince12e49462014-06-09 13:29:32 -0500286
Vince Lehman76c751c2014-11-18 17:36:38 -0600287 RibTable::iterator nextIt = m_rib.erase(it);
Vince12e49462014-06-09 13:29:32 -0500288
Yanbiao Lic17de832014-11-21 17:51:45 -0800289 // do something after erasing an entry.
290 afterEraseEntry(entry->getName());
291
Vince12e49462014-06-09 13:29:32 -0500292 return nextIt;
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700293}
294
Vince Lehman218be0a2015-01-15 17:25:20 -0600295Rib::RouteSet
296Rib::getAncestorRoutes(const RibEntry& entry) const
Vince Lehman4387e782014-06-19 16:57:45 -0500297{
Vince Lehman218be0a2015-01-15 17:25:20 -0600298 RouteSet ancestorRoutes(&sortRoutes);
Vince Lehman4387e782014-06-19 16:57:45 -0500299
300 shared_ptr<RibEntry> parent = entry.getParent();
301
Vince Lehman76c751c2014-11-18 17:36:38 -0600302 while (parent != nullptr) {
303 for (const Route& route : parent->getRoutes()) {
304 if (route.isChildInherit()) {
305 ancestorRoutes.insert(route);
Vince Lehman4387e782014-06-19 16:57:45 -0500306 }
Vince Lehman4387e782014-06-19 16:57:45 -0500307 }
308
Vince Lehman76c751c2014-11-18 17:36:38 -0600309 if (parent->hasCapture()) {
310 break;
Vince Lehman4387e782014-06-19 16:57:45 -0500311 }
Vince Lehman76c751c2014-11-18 17:36:38 -0600312
313 parent = parent->getParent();
314 }
315
316 return ancestorRoutes;
317}
318
319Rib::RouteSet
320Rib::getAncestorRoutes(const Name& name) const
321{
322 RouteSet ancestorRoutes(&sortRoutes);
323
324 shared_ptr<RibEntry> parent = findParent(name);
325
326 while (parent != nullptr) {
327 for (const Route& route : parent->getRoutes()) {
328 if (route.isChildInherit()) {
329 ancestorRoutes.insert(route);
330 }
331 }
332
333 if (parent->hasCapture()) {
334 break;
335 }
336
337 parent = parent->getParent();
338 }
339
340 return ancestorRoutes;
341}
342
343void
344Rib::beginApplyUpdate(const RibUpdate& update,
345 const Rib::UpdateSuccessCallback& onSuccess,
346 const Rib::UpdateFailureCallback& onFailure)
347{
348 BOOST_ASSERT(m_fibUpdater != nullptr);
349
350 addUpdateToQueue(update, onSuccess, onFailure);
351
352 sendBatchFromQueue();
353}
354
355void
356Rib::beginRemoveFace(uint64_t faceId)
357{
358 for (const auto& nameAndRoute : findRoutesWithFaceId(faceId)) {
359 RibUpdate update;
360 update.setAction(RibUpdate::REMOVE_FACE)
361 .setName(nameAndRoute.first)
362 .setRoute(nameAndRoute.second);
363
364 addUpdateToQueue(update, nullptr, nullptr);
365 }
366
367 sendBatchFromQueue();
368}
369
370void
371Rib::addUpdateToQueue(const RibUpdate& update,
372 const Rib::UpdateSuccessCallback& onSuccess,
373 const Rib::UpdateFailureCallback& onFailure)
374{
375 RibUpdateBatch batch(update.getRoute().faceId);
376 batch.add(update);
377
378 UpdateQueueItem item{batch, onSuccess, onFailure};
379 m_updateBatches.push_back(std::move(item));
380}
381
382void
383Rib::sendBatchFromQueue()
384{
385 if (m_updateBatches.empty() || m_isUpdateInProgress) {
386 return;
387 }
388
389 m_isUpdateInProgress = true;
390
391 UpdateQueueItem item = std::move(m_updateBatches.front());
392 m_updateBatches.pop_front();
393
394 RibUpdateBatch& batch = item.batch;
395
396 // Until task #1698, each RibUpdateBatch contains exactly one RIB update
397 BOOST_ASSERT(batch.size() == 1);
398
399 const Rib::UpdateSuccessCallback& managerSuccessCallback = item.managerSuccessCallback;
400 const Rib::UpdateFailureCallback& managerFailureCallback = item.managerFailureCallback;
401
402 m_fibUpdater->computeAndSendFibUpdates(batch,
403 bind(&Rib::onFibUpdateSuccess, this,
404 batch, _1, managerSuccessCallback),
405 bind(&Rib::onFibUpdateFailure, this,
406 managerFailureCallback, _1, _2));
407
408 if (m_onSendBatchFromQueue != nullptr) {
409 m_onSendBatchFromQueue(batch);
410 }
411}
412
413void
414Rib::onFibUpdateSuccess(const RibUpdateBatch& batch,
415 const RibUpdateList& inheritedRoutes,
416 const Rib::UpdateSuccessCallback& onSuccess)
417{
418 for (const RibUpdate& update : batch) {
419 switch (update.getAction()) {
420 case RibUpdate::REGISTER:
421 insert(update.getName(), update.getRoute());
422 break;
423 case RibUpdate::UNREGISTER:
424 case RibUpdate::REMOVE_FACE:
425 erase(update.getName(), update.getRoute());
426 break;
427 }
428 }
429
430 // Add and remove precalculated inherited routes to RibEntries
431 modifyInheritedRoutes(inheritedRoutes);
432
433 m_isUpdateInProgress = false;
434
435 if (onSuccess != nullptr) {
436 onSuccess();
437 }
438
439 // Try to advance the batch queue
440 sendBatchFromQueue();
441}
442
443void
444Rib::onFibUpdateFailure(const Rib::UpdateFailureCallback& onFailure,
445 uint32_t code, const std::string& error)
446{
447 m_isUpdateInProgress = false;
448
449 if (onFailure != nullptr) {
450 onFailure(code, error);
451 }
452
453 // Try to advance the batch queue
454 sendBatchFromQueue();
455}
456
457void
458Rib::modifyInheritedRoutes(const RibUpdateList& inheritedRoutes)
459{
460 for (const RibUpdate& update : inheritedRoutes) {
461 RibTable::iterator ribIt = m_rib.find(update.getName());
462
463 BOOST_ASSERT(ribIt != m_rib.end());
464 shared_ptr<RibEntry> entry(ribIt->second);
465
466 switch (update.getAction()) {
467 case RibUpdate::REGISTER:
468 entry->addInheritedRoute(update.getRoute());
469 break;
470 case RibUpdate::UNREGISTER:
471 entry->removeInheritedRoute(update.getRoute());
472 break;
473 case RibUpdate::REMOVE_FACE:
474 break;
475 }
476 }
477}
478
479std::list<Rib::NameAndRoute>
480Rib::findRoutesWithFaceId(uint64_t faceId)
481{
482 std::list<NameAndRoute> routes;
483
484 FaceLookupTable::iterator lookupIt = m_faceMap.find(faceId);
485
486 // No RIB entries have this face
487 if (lookupIt == m_faceMap.end()) {
488 return routes;
489 }
490
491 RibEntryList& ribEntries = lookupIt->second;
492
493 // For each RIB entry that has faceId
494 for (const shared_ptr<RibEntry>& entry : ribEntries) {
495 // Find the routes in the entry
496 for (const Route& route : *entry) {
497 if (route.faceId == faceId) {
498 routes.push_back(NameAndRoute(entry->getName(), route));
499 }
500 }
501 }
502
503 return routes;
Vince Lehman4387e782014-06-19 16:57:45 -0500504}
505
Alexander Afanasyev20d31442014-04-19 17:00:53 -0700506std::ostream&
Vince12e49462014-06-09 13:29:32 -0500507operator<<(std::ostream& os, const Rib& rib)
Alexander Afanasyev20d31442014-04-19 17:00:53 -0700508{
Vince Lehman76c751c2014-11-18 17:36:38 -0600509 for (const auto& item : rib) {
510 os << item.second << "\n";
511 }
Alexander Afanasyev20d31442014-04-19 17:00:53 -0700512
513 return os;
514}
515
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700516} // namespace rib
517} // namespace nfd