blob: 5c18b77f227a8ea2761d88e99e08d18c8472a2a0 [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2016, 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");
static bool
npteCompare(NamePrefixTableEntry& npte, const ndn::Name& name)
{
return npte.getNamePrefix() == name;
}
void
NamePrefixTable::addEntry(const ndn::Name& name, RoutingTableEntry& rte)
{
// Check if the advertised name prefix is in the table already.
NptEntryList::iterator it = std::find_if(m_table.begin(),
m_table.end(),
bind(&npteCompare, _1, name));
// If not, create a new entry and add it.
if (it == m_table.end()) {
_LOG_TRACE("Adding origin: " << rte.getDestination() << " to new name prefix: " << name);
NamePrefixTableEntry entry(name);
entry.addRoutingTableEntry(rte); // Add this RTE to this new NPT entry.
entry.generateNhlfromRteList(); // Generate a list of next-hops from the RTE.
m_table.push_back(entry); // Add the new, completed entry into the main table.
// If the RTE we added has any next hops, we inform the FIB of this.
if (rte.getNexthopList().getSize() > 0) {
_LOG_TRACE("Updating FIB with next hops for " << entry);
m_nlsr.getFib().update(name, entry.getNexthopList());
}
}
else {
_LOG_TRACE("Adding origin: " << rte.getDestination() << " to existing prefix: " << *it);
// Update the existing entry with the new RTE.
it->addRoutingTableEntry(rte);
it->generateNhlfromRteList();
// As above, inform the FIB of this fact.
// We may possibly have a new best next-hop for this name prefix
// So this is a necessary step.
if (it->getNexthopList().getSize() > 0) {
_LOG_TRACE("Updating FIB with next hops for " << *it);
m_nlsr.getFib().update(name, it->getNexthopList());
}
else {
// 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.
_LOG_TRACE(*it << " has no next hops; removing from FIB");
m_nlsr.getFib().remove(name);
}
}
}
void
NamePrefixTable::removeEntry(const ndn::Name& name, RoutingTableEntry& rte)
{
NptEntryList::iterator it = std::find_if(m_table.begin(),
m_table.end(),
bind(&npteCompare, _1, name));
if (it != m_table.end()) {
_LOG_TRACE("Removing origin: " << rte.getDestination() << " from prefix: " << *it);
it->removeRoutingTableEntry(rte);
// 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 (it->getRteListSize() == 0) {
_LOG_TRACE(*it << " has no routing table entries; removing from table and FIB");
m_table.erase(it);
m_nlsr.getFib().remove(name);
}
else {
_LOG_TRACE(*it << " has other routing table entries; updating FIB with next hops");
it->generateNhlfromRteList();
m_nlsr.getFib().update(name, it->getNexthopList());
}
}
}
void
NamePrefixTable::addEntry(const ndn::Name& name, const ndn::Name& destRouter)
{
_LOG_DEBUG("Adding origin: " << destRouter << " to " << name);
RoutingTableEntry* rteCheck = m_nlsr.getRoutingTable().findRoutingTableEntry(destRouter);
if (rteCheck != nullptr) {
addEntry(name, *rteCheck);
}
else {
RoutingTableEntry rte(destRouter);
addEntry(name, rte);
}
}
void
NamePrefixTable::removeEntry(const ndn::Name& name, const ndn::Name& destRouter)
{
_LOG_DEBUG("Removing origin: " << destRouter << " from " << name);
RoutingTableEntry* rteCheck = m_nlsr.getRoutingTable().findRoutingTableEntry(destRouter);
if (rteCheck != nullptr) {
removeEntry(name, *rteCheck);
}
else {
RoutingTableEntry rte(destRouter);
removeEntry(name, rte);
}
}
void
NamePrefixTable::updateWithNewRoute()
{
_LOG_DEBUG("Updating table with newly calculated routes");
// Update each name prefix entry in the Name Prefix Table with newly calculated next hops
// For each entry in the NPT
for (const NamePrefixTableEntry& prefixEntry : m_table) {
// For each routing table entry
for (const RoutingTableEntry& routingEntry : prefixEntry.getRteList()) {
_LOG_TRACE("Updating next hops to origin: " << routingEntry.getDestination()
<< " for prefix: " << prefixEntry);
RoutingTableEntry* rteCheck =
m_nlsr.getRoutingTable().findRoutingTableEntry(routingEntry.getDestination());
// If there is a routing table entry for this prefix, update the NPT with it.
if (rteCheck != nullptr) {
addEntry(prefixEntry.getNamePrefix(), *rteCheck);
}
else {
RoutingTableEntry rte(routingEntry.getDestination());
addEntry(prefixEntry.getNamePrefix(), rte);
}
}
}
}
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