blob: bd7269af63cd973729a5f819206db894a7b04718 [file] [log] [blame]
akmhoque3d06e792014-05-27 16:23:20 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Nick Gordonfeae5572017-01-13 12:06:26 -06003 * Copyright (c) 2014-2017, The University of Memphis,
Vince Lehmanc2e51f62015-01-20 15:03:11 -06004 * Regents of the University of California,
5 * Arizona Board of Regents.
akmhoque3d06e792014-05-27 16:23:20 -05006 *
7 * This file is part of NLSR (Named-data Link State Routing).
8 * See AUTHORS.md for complete list of NLSR authors and contributors.
9 *
10 * NLSR is free software: you can redistribute it and/or modify it under the terms
11 * of the GNU General Public License as published by the Free Software Foundation,
12 * either version 3 of the License, or (at your option) any later version.
13 *
14 * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
15 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 * PURPOSE. See the GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * NLSR, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
akmhoque3d06e792014-05-27 16:23:20 -050020 **/
Vince Lehmanc2e51f62015-01-20 15:03:11 -060021
Vince Lehmancae33b62015-06-05 09:21:30 -050022#include "name-prefix-table.hpp"
23
24#include "logger.hpp"
25#include "nlsr.hpp"
26#include "routing-table.hpp"
27
28#include <algorithm>
akmhoque53353462014-04-22 08:43:45 -050029#include <list>
30#include <utility>
akmhoque53353462014-04-22 08:43:45 -050031
32namespace nlsr {
33
akmhoque674b0b12014-05-20 14:33:28 -050034INIT_LOGGER("NamePrefixTable");
35
Nick Gordonb7b58392017-08-17 16:29:21 -050036NamePrefixTable::NamePrefixTable(Nlsr& nlsr, std::shared_ptr<AfterRoutingChange>& afterRoutingChangeSignal)
37 : m_nlsr(nlsr)
38{
39 m_afterRoutingChangeConnection = afterRoutingChangeSignal->connect(
40 [this] (const std::list<RoutingTableEntry>& entries) {
41 updateWithNewRoute(entries);
42 });
43}
44
45NamePrefixTable::~NamePrefixTable()
46{
47 m_afterRoutingChangeConnection.disconnect();
48}
49
Nick Gordonb50e51b2016-07-22 16:05:57 -050050bool
Nick Gordonc0c6bcf2017-08-15 18:11:21 -050051npteCompare(std::shared_ptr<NamePrefixTableEntry>& npte, const ndn::Name& name)
akmhoque53353462014-04-22 08:43:45 -050052{
Nick Gordonc0c6bcf2017-08-15 18:11:21 -050053 return npte->getNamePrefix() == name;
akmhoque53353462014-04-22 08:43:45 -050054}
55
akmhoque53353462014-04-22 08:43:45 -050056void
akmhoque31d1d4b2014-05-05 22:08:14 -050057NamePrefixTable::addEntry(const ndn::Name& name, const ndn::Name& destRouter)
akmhoque53353462014-04-22 08:43:45 -050058{
Vince Lehmancae33b62015-06-05 09:21:30 -050059
Nick Gordonb50e51b2016-07-22 16:05:57 -050060 // Check if the advertised name prefix is in the table already.
Nick Gordonc0c6bcf2017-08-15 18:11:21 -050061 NptEntryList::iterator nameItr =
62 std::find_if(m_table.begin(),
63 m_table.end(),
64 [&] (const std::shared_ptr<NamePrefixTableEntry>& entry) {
65 return name == entry->getNamePrefix();
66 });
Vince Lehmancae33b62015-06-05 09:21:30 -050067
Nick Gordonb50e51b2016-07-22 16:05:57 -050068 // Attempt to find a routing table pool entry (RTPE) we can use.
Nick Gordonc0c6bcf2017-08-15 18:11:21 -050069 RoutingTableEntryPool::iterator rtpeItr = m_rtpool.find(destRouter);
Nick Gordonb50e51b2016-07-22 16:05:57 -050070
71 // These declarations just to make the compiler happy...
72 RoutingTablePoolEntry rtpe;
73 std::shared_ptr<RoutingTablePoolEntry> rtpePtr(nullptr);
74
75 // There isn't currently a routing table entry in the pool for this name
76 if (rtpeItr == m_rtpool.end()) {
77 // See if there is a routing table entry available we could use
78 RoutingTableEntry* routeEntryPtr = m_nlsr.getRoutingTable()
79 .findRoutingTableEntry(destRouter);
80
81 // We have to create a new routing table entry
82 if (routeEntryPtr == nullptr) {
83 rtpe = RoutingTablePoolEntry(destRouter, 0);
84 }
85 // There was already a usable one in the routing table
86 else {
87 rtpe = RoutingTablePoolEntry(*routeEntryPtr, 0);
88 }
89
90 // Add the new pool object to the pool.
91 rtpePtr = addRtpeToPool(rtpe);
92 }
93 // There was one already, so just fetch that one.
94 else {
95 rtpePtr = (*rtpeItr).second;
96 }
97
Nick Gordonc0c6bcf2017-08-15 18:11:21 -050098 std::shared_ptr<NamePrefixTableEntry> npte;
Nick Gordonb50e51b2016-07-22 16:05:57 -050099 // Either we have to make a new NPT entry or there already was one.
100 if (nameItr == m_table.end()) {
101 _LOG_DEBUG("Adding origin: " << rtpePtr->getDestination()
102 << " to a new name prefix: " << name);
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500103 npte = make_shared<NamePrefixTableEntry>(name);
104 npte->addRoutingTableEntry(rtpePtr);
105 npte->generateNhlfromRteList();
Nick Gordonb50e51b2016-07-22 16:05:57 -0500106 m_table.push_back(npte);
Nick Gordonb50e51b2016-07-22 16:05:57 -0500107 // If this entry has next hops, we need to inform the FIB
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500108 if (npte->getNexthopList().getSize() > 0) {
Nick Gordonb50e51b2016-07-22 16:05:57 -0500109 _LOG_TRACE("Updating FIB with next hops for " << npte);
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500110 m_nlsr.getFib().update(name, npte->getNexthopList());
Nick Gordonb50e51b2016-07-22 16:05:57 -0500111 }
112 // The routing table may recalculate and add a routing table entry
113 // with no next hops to replace an existing routing table entry. In
114 // this case, the name prefix is no longer reachable through a next
115 // hop and should be removed from the FIB. But, the prefix should
116 // remain in the Name Prefix Table as a future routing table
117 // calculation may add next hops.
118 else {
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500119 _LOG_TRACE(*npte << " has no next hops; removing from FIB");
Nick Gordonb50e51b2016-07-22 16:05:57 -0500120 m_nlsr.getFib().remove(name);
121 }
akmhoque53353462014-04-22 08:43:45 -0500122 }
akmhoque157b0a42014-05-13 00:26:37 -0500123 else {
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500124 npte = *nameItr;
Nick Gordonb50e51b2016-07-22 16:05:57 -0500125 _LOG_TRACE("Adding origin: " << rtpePtr->getDestination()
126 << " to existing prefix: " << *nameItr);
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500127 (*nameItr)->addRoutingTableEntry(rtpePtr);
128 (*nameItr)->generateNhlfromRteList();
Nick Gordonb50e51b2016-07-22 16:05:57 -0500129
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500130 if ((*nameItr)->getNexthopList().getSize() > 0) {
Nick Gordonb50e51b2016-07-22 16:05:57 -0500131 _LOG_TRACE("Updating FIB with next hops for " << (*nameItr));
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500132 m_nlsr.getFib().update(name, (*nameItr)->getNexthopList());
Nick Gordonb50e51b2016-07-22 16:05:57 -0500133 }
134 else {
135 _LOG_TRACE((*nameItr) << " has no next hops; removing from FIB");
136 m_nlsr.getFib().remove(name);
137 }
akmhoque53353462014-04-22 08:43:45 -0500138 }
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500139 // Add the reference to this NPT to the RTPE.
140 rtpePtr->namePrefixTableEntries.emplace(
141 std::make_pair(npte->getNamePrefix(), std::weak_ptr<NamePrefixTableEntry>(npte)));
akmhoque53353462014-04-22 08:43:45 -0500142}
143
144void
akmhoque31d1d4b2014-05-05 22:08:14 -0500145NamePrefixTable::removeEntry(const ndn::Name& name, const ndn::Name& destRouter)
akmhoque53353462014-04-22 08:43:45 -0500146{
Vince Lehmancae33b62015-06-05 09:21:30 -0500147 _LOG_DEBUG("Removing origin: " << destRouter << " from " << name);
148
Nick Gordonb50e51b2016-07-22 16:05:57 -0500149 // Fetch an iterator to the appropriate pair object in the pool.
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500150 RoutingTableEntryPool::iterator rtpeItr = m_rtpool.find(destRouter);
Vince Lehmancae33b62015-06-05 09:21:30 -0500151
Nick Gordonb50e51b2016-07-22 16:05:57 -0500152 // Simple error checking to prevent any unusual behavior in the case
153 // that we try to remove an entry that isn't there.
154 if (rtpeItr == m_rtpool.end()) {
155 _LOG_DEBUG("No entry for origin: " << destRouter
156 << " found, so it cannot be removed from prefix: "
157 << name);
158 return;
159 }
160 std::shared_ptr<RoutingTablePoolEntry> rtpePtr = rtpeItr->second;
161
162 // Ensure that the entry exists
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500163 NptEntryList::iterator nameItr =
164 std::find_if(m_table.begin(), m_table.end(),
165 [&] (const std::shared_ptr<NamePrefixTableEntry>& entry) {
166 return entry->getNamePrefix() == name;
167 });
Nick Gordonb50e51b2016-07-22 16:05:57 -0500168 if (nameItr != m_table.end()) {
169 _LOG_TRACE("Removing origin: " << rtpePtr->getDestination()
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500170 << " from prefix: " << **nameItr);
Nick Gordonb50e51b2016-07-22 16:05:57 -0500171
172 // Rather than iterating through the whole list periodically, just
173 // delete them here if they have no references.
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500174 if ((*nameItr)->removeRoutingTableEntry(rtpePtr) == 0) {
Nick Gordonb50e51b2016-07-22 16:05:57 -0500175 deleteRtpeFromPool(rtpePtr);
176 }
177
178 // If the prefix is a router prefix and it does not have any other
179 // routing table entries, the Adjacency/Coordinate LSA associated
180 // with that origin router has been removed from the LSDB and so
181 // the router prefix should be removed from the Name Prefix Table.
182 //
183 // If the prefix is an advertised name prefix: If another router
184 // advertises this name prefix, the RteList should have another
185 // entry for that router; the next hops should be recalculated
186 // and installed in the FIB.
187 //
188 // If no other router advertises this name prefix, the RteList
189 // should be empty and the prefix can be removed from the Name
190 // Prefix Table. Once a new Name LSA advertises this prefix, a
191 // new entry for the prefix will be created.
192 //
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500193 if ((*nameItr)->getRteListSize() == 0) {
194 _LOG_TRACE(**nameItr << " has no routing table entries;"
Nick Gordonb50e51b2016-07-22 16:05:57 -0500195 << " removing from table and FIB");
196 m_table.erase(nameItr);
197 m_nlsr.getFib().remove(name);
198 }
199 else {
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500200 _LOG_TRACE(**nameItr << " has other routing table entries;"
Nick Gordonb50e51b2016-07-22 16:05:57 -0500201 << " updating FIB with next hops");
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500202 (*nameItr)->generateNhlfromRteList();
203 m_nlsr.getFib().update(name, (*nameItr)->getNexthopList());
Nick Gordonb50e51b2016-07-22 16:05:57 -0500204 }
akmhoque53353462014-04-22 08:43:45 -0500205 }
akmhoque157b0a42014-05-13 00:26:37 -0500206 else {
Nick Gordonb50e51b2016-07-22 16:05:57 -0500207 _LOG_DEBUG("Attempted to remove origin: " << rtpePtr->getDestination()
Ashlesh Gawande90173ad2017-08-09 15:19:50 -0500208 << " from non-existent prefix: " << name);
akmhoque53353462014-04-22 08:43:45 -0500209 }
210}
211
212void
Nick Gordonb7b58392017-08-17 16:29:21 -0500213NamePrefixTable::updateWithNewRoute(const std::list<RoutingTableEntry>& entries)
akmhoque53353462014-04-22 08:43:45 -0500214{
Vince Lehmancae33b62015-06-05 09:21:30 -0500215 _LOG_DEBUG("Updating table with newly calculated routes");
216
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500217 // Iterate over each pool entry we have
218 for (auto&& poolEntryPair : m_rtpool) {
219 auto&& poolEntry = poolEntryPair.second;
Nick Gordonb7b58392017-08-17 16:29:21 -0500220 auto sourceEntry = std::find_if(entries.begin(), entries.end(),
221 [&poolEntry] (const RoutingTableEntry& entry) {
222 return poolEntry->getDestination() == entry.getDestination();
223 });
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500224 // If this pool entry has a corresponding entry in the routing table now
Nick Gordonb7b58392017-08-17 16:29:21 -0500225 if (sourceEntry != entries.end()
226 && poolEntry->getNexthopList() != sourceEntry->getNexthopList()) {
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500227 _LOG_DEBUG("Routing entry: " << poolEntry->getDestination() << " has changed next-hops.");
228 poolEntry->setNexthopList(sourceEntry->getNexthopList());
229 for (const auto& nameEntry : poolEntry->namePrefixTableEntries) {
230 auto nameEntryFullPtr = nameEntry.second.lock();
231 addEntry(nameEntryFullPtr->getNamePrefix(), poolEntry->getDestination());
232 }
233 }
Nick Gordonb7b58392017-08-17 16:29:21 -0500234 else if (sourceEntry == entries.end()) {
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500235 _LOG_DEBUG("Routing entry: " << poolEntry->getDestination() << " now has no next-hops.");
236 poolEntry->getNexthopList().reset();
237 for (const auto& nameEntry : poolEntry->namePrefixTableEntries) {
238 auto nameEntryFullPtr = nameEntry.second.lock();
239 addEntry(nameEntryFullPtr->getNamePrefix(), poolEntry->getDestination());
240 }
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500241 }
242 else {
243 _LOG_TRACE("No change in routing entry:" << poolEntry->getDestination()
244 << ", no action necessary.");
akmhoque53353462014-04-22 08:43:45 -0500245 }
246 }
247}
248
Nick Gordonb50e51b2016-07-22 16:05:57 -0500249 // Inserts the routing table pool entry into the NPT's RTE storage
250 // pool. This cannot fail, so the pool is guaranteed to contain the
251 // item after this occurs.
252std::shared_ptr<RoutingTablePoolEntry>
253NamePrefixTable::addRtpeToPool(RoutingTablePoolEntry& rtpe)
254{
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500255 RoutingTableEntryPool::iterator poolItr =
Nick Gordonb50e51b2016-07-22 16:05:57 -0500256 m_rtpool.insert(std::make_pair(rtpe.getDestination(),
257 std::make_shared<RoutingTablePoolEntry>
258 (rtpe)))
259 .first;
Nick Gordonb50e51b2016-07-22 16:05:57 -0500260 return poolItr->second;
261}
262
263 // Removes the routing table pool entry from the storage pool. The
264 // postconditions of this function are guaranteed to include that
265 // the storage pool does not contain such an item. Additionally,
266 // this function cannot fail, but nonetheless debug information is
267 // given in the case that this function is called with an entry that
268 // isn't in the pool.
269void
270NamePrefixTable::deleteRtpeFromPool(std::shared_ptr<RoutingTablePoolEntry> rtpePtr)
271{
272 if (m_rtpool.erase(rtpePtr->getDestination()) != 1) {
Ashlesh Gawande90173ad2017-08-09 15:19:50 -0500273 _LOG_DEBUG("Attempted to delete non-existent origin: "
Nick Gordonb50e51b2016-07-22 16:05:57 -0500274 << rtpePtr->getDestination()
275 << " from NPT routing table entry storage pool.");
276 }
277}
278
akmhoque53353462014-04-22 08:43:45 -0500279void
akmhoque674b0b12014-05-20 14:33:28 -0500280NamePrefixTable::writeLog()
281{
Vince Lehmancae33b62015-06-05 09:21:30 -0500282 _LOG_DEBUG(*this);
akmhoque674b0b12014-05-20 14:33:28 -0500283}
284
Vince Lehmancae33b62015-06-05 09:21:30 -0500285std::ostream&
286operator<<(std::ostream& os, const NamePrefixTable& table)
287{
288 os << "----------------NPT----------------------\n";
289
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500290 for (const auto& entryPtr : table) {
291 os << *entryPtr << std::endl;
Vince Lehmancae33b62015-06-05 09:21:30 -0500292 }
293
294 return os;
295}
296
297} // namespace nlsr