blob: 646779012f2d781602540645a7920dc6426df46d [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2017, The University of Memphis,
* Regents of the University of California,
* Arizona Board of Regents.
*
* This file is part of NLSR (Named-data Link State Routing).
* See AUTHORS.md for complete list of NLSR authors and contributors.
*
* NLSR is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NLSR, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
**/
#include "name-prefix-table.hpp"
#include "logger.hpp"
#include "nlsr.hpp"
#include "routing-table.hpp"
#include <algorithm>
#include <list>
#include <utility>
namespace nlsr {
INIT_LOGGER("NamePrefixTable");
bool
npteCompare(NamePrefixTableEntry& npte, const ndn::Name& name)
{
return npte.getNamePrefix() == name;
}
void
NamePrefixTable::addEntry(const ndn::Name& name, const ndn::Name& destRouter)
{
// Check if the advertised name prefix is in the table already.
NptEntryList::iterator nameItr = std::find(m_table.begin(),
m_table.end(),
name);
// Attempt to find a routing table pool entry (RTPE) we can use.
RtpEntryMap::iterator rtpeItr = m_rtpool.find(destRouter);
// These declarations just to make the compiler happy...
RoutingTablePoolEntry rtpe;
std::shared_ptr<RoutingTablePoolEntry> rtpePtr(nullptr);
// There isn't currently a routing table entry in the pool for this name
if (rtpeItr == m_rtpool.end()) {
// See if there is a routing table entry available we could use
RoutingTableEntry* routeEntryPtr = m_nlsr.getRoutingTable()
.findRoutingTableEntry(destRouter);
// We have to create a new routing table entry
if (routeEntryPtr == nullptr) {
rtpe = RoutingTablePoolEntry(destRouter, 0);
}
// There was already a usable one in the routing table
else {
rtpe = RoutingTablePoolEntry(*routeEntryPtr, 0);
}
// Add the new pool object to the pool.
rtpePtr = addRtpeToPool(rtpe);
}
// There was one already, so just fetch that one.
else {
rtpePtr = (*rtpeItr).second;
}
// Either we have to make a new NPT entry or there already was one.
if (nameItr == m_table.end()) {
_LOG_DEBUG("Adding origin: " << rtpePtr->getDestination()
<< " to a new name prefix: " << name);
NamePrefixTableEntry npte(name);
npte.addRoutingTableEntry(rtpePtr);
npte.generateNhlfromRteList();
m_table.push_back(npte);
// If this entry has next hops, we need to inform the FIB
if (npte.getNexthopList().getSize() > 0) {
_LOG_TRACE("Updating FIB with next hops for " << npte);
m_nlsr.getFib().update(name, npte.getNexthopList());
}
// The routing table may recalculate and add a routing table entry
// with no next hops to replace an existing routing table entry. In
// this case, the name prefix is no longer reachable through a next
// hop and should be removed from the FIB. But, the prefix should
// remain in the Name Prefix Table as a future routing table
// calculation may add next hops.
else {
_LOG_TRACE(npte << " has no next hops; removing from FIB");
m_nlsr.getFib().remove(name);
}
}
else {
_LOG_TRACE("Adding origin: " << rtpePtr->getDestination()
<< " to existing prefix: " << *nameItr);
nameItr->addRoutingTableEntry(rtpePtr);
nameItr->generateNhlfromRteList();
if (nameItr->getNexthopList().getSize() > 0) {
_LOG_TRACE("Updating FIB with next hops for " << (*nameItr));
m_nlsr.getFib().update(name, nameItr->getNexthopList());
}
else {
_LOG_TRACE((*nameItr) << " has no next hops; removing from FIB");
m_nlsr.getFib().remove(name);
}
}
}
void
NamePrefixTable::removeEntry(const ndn::Name& name, const ndn::Name& destRouter)
{
_LOG_DEBUG("Removing origin: " << destRouter << " from " << name);
// Fetch an iterator to the appropriate pair object in the pool.
RtpEntryMap::iterator rtpeItr = m_rtpool.find(destRouter);
// Simple error checking to prevent any unusual behavior in the case
// that we try to remove an entry that isn't there.
if (rtpeItr == m_rtpool.end()) {
_LOG_DEBUG("No entry for origin: " << destRouter
<< " found, so it cannot be removed from prefix: "
<< name);
return;
}
std::shared_ptr<RoutingTablePoolEntry> rtpePtr = rtpeItr->second;
// Ensure that the entry exists
NptEntryList::iterator nameItr = std::find_if(m_table.begin(),
m_table.end(),
std::bind(&npteCompare, _1, name));
if (nameItr != m_table.end()) {
_LOG_TRACE("Removing origin: " << rtpePtr->getDestination()
<< " from prefix: " << *nameItr);
// Rather than iterating through the whole list periodically, just
// delete them here if they have no references.
if ((*nameItr).removeRoutingTableEntry(rtpePtr) == 0) {
deleteRtpeFromPool(rtpePtr);
}
// If the prefix is a router prefix and it does not have any other
// routing table entries, the Adjacency/Coordinate LSA associated
// with that origin router has been removed from the LSDB and so
// the router prefix should be removed from the Name Prefix Table.
//
// If the prefix is an advertised name prefix: If another router
// advertises this name prefix, the RteList should have another
// entry for that router; the next hops should be recalculated
// and installed in the FIB.
//
// If no other router advertises this name prefix, the RteList
// should be empty and the prefix can be removed from the Name
// Prefix Table. Once a new Name LSA advertises this prefix, a
// new entry for the prefix will be created.
//
if ((*nameItr).getRteListSize() == 0) {
_LOG_TRACE(*nameItr << " has no routing table entries;"
<< " removing from table and FIB");
m_table.erase(nameItr);
m_nlsr.getFib().remove(name);
}
else {
_LOG_TRACE(*nameItr << " has other routing table entries;"
<< " updating FIB with next hops");
(*nameItr).generateNhlfromRteList();
m_nlsr.getFib().update(name, (*nameItr).getNexthopList());
}
}
else {
_LOG_DEBUG("Attempted to remove origin: " << rtpePtr->getDestination()
<< " from non-existant prefix: " << name);
}
}
void
NamePrefixTable::updateWithNewRoute()
{
_LOG_DEBUG("Updating table with newly calculated routes");
// Update each name prefix table entry in the NPT with the
// newly calculated next hops.
for (auto&& npte : m_table) {
// For each routing table pool entry in this NPT entry.
for (auto&& rtpe : npte.getRteList()) {
_LOG_TRACE("Updating next hops to origin: " << rtpe->getDestination()
<< " for prefix: " << npte);
RoutingTableEntry* rteCheck =
m_nlsr.getRoutingTable().findRoutingTableEntry(rtpe->getDestination());
// If there is a routing table entry for this prefix, update the NPT with it.
if (rteCheck != nullptr) {
rtpe->setNexthopList(rteCheck->getNexthopList());
}
else {
rtpe->getNexthopList().reset();
}
addEntry(npte.getNamePrefix(), rtpe->getDestination());
}
}
}
// Inserts the routing table pool entry into the NPT's RTE storage
// pool. This cannot fail, so the pool is guaranteed to contain the
// item after this occurs.
std::shared_ptr<RoutingTablePoolEntry>
NamePrefixTable::addRtpeToPool(RoutingTablePoolEntry& rtpe)
{
RtpEntryMap::iterator poolItr =
m_rtpool.insert(std::make_pair(rtpe.getDestination(),
std::make_shared<RoutingTablePoolEntry>
(rtpe)))
.first;
//| There's gotta be a more efficient way to do this
//std::shared_ptr<RoutingTablePoolEntry> poolPtr = &(poolItr->second);
return poolItr->second;
}
// Removes the routing table pool entry from the storage pool. The
// postconditions of this function are guaranteed to include that
// the storage pool does not contain such an item. Additionally,
// this function cannot fail, but nonetheless debug information is
// given in the case that this function is called with an entry that
// isn't in the pool.
void
NamePrefixTable::deleteRtpeFromPool(std::shared_ptr<RoutingTablePoolEntry> rtpePtr)
{
if (m_rtpool.erase(rtpePtr->getDestination()) != 1) {
_LOG_DEBUG("Attempted to delete non-existant origin: "
<< rtpePtr->getDestination()
<< " from NPT routing table entry storage pool.");
}
}
void
NamePrefixTable::writeLog()
{
_LOG_DEBUG(*this);
}
std::ostream&
operator<<(std::ostream& os, const NamePrefixTable& table)
{
os << "----------------NPT----------------------\n";
for (const NamePrefixTableEntry& entry : table) {
os << entry << std::endl;
}
return os;
}
} // namespace nlsr