blob: 4f9d91d929bd45bf39c84aa1fa94ed921118e769 [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 Gordond40a5882017-09-05 15:34:58 -050036NamePrefixTable::NamePrefixTable(Nlsr& nlsr,
37 std::unique_ptr<AfterRoutingChange>& afterRoutingChangeSignal)
Nick Gordonb7b58392017-08-17 16:29:21 -050038 : m_nlsr(nlsr)
39{
40 m_afterRoutingChangeConnection = afterRoutingChangeSignal->connect(
41 [this] (const std::list<RoutingTableEntry>& entries) {
42 updateWithNewRoute(entries);
43 });
44}
45
46NamePrefixTable::~NamePrefixTable()
47{
48 m_afterRoutingChangeConnection.disconnect();
49}
50
Nick Gordonb50e51b2016-07-22 16:05:57 -050051bool
Nick Gordonc0c6bcf2017-08-15 18:11:21 -050052npteCompare(std::shared_ptr<NamePrefixTableEntry>& npte, const ndn::Name& name)
akmhoque53353462014-04-22 08:43:45 -050053{
Nick Gordonc0c6bcf2017-08-15 18:11:21 -050054 return npte->getNamePrefix() == name;
akmhoque53353462014-04-22 08:43:45 -050055}
56
akmhoque53353462014-04-22 08:43:45 -050057void
akmhoque31d1d4b2014-05-05 22:08:14 -050058NamePrefixTable::addEntry(const ndn::Name& name, const ndn::Name& destRouter)
akmhoque53353462014-04-22 08:43:45 -050059{
Vince Lehmancae33b62015-06-05 09:21:30 -050060
Nick Gordonb50e51b2016-07-22 16:05:57 -050061 // Check if the advertised name prefix is in the table already.
Nick Gordonc0c6bcf2017-08-15 18:11:21 -050062 NptEntryList::iterator nameItr =
63 std::find_if(m_table.begin(),
64 m_table.end(),
65 [&] (const std::shared_ptr<NamePrefixTableEntry>& entry) {
66 return name == entry->getNamePrefix();
67 });
Vince Lehmancae33b62015-06-05 09:21:30 -050068
Nick Gordonb50e51b2016-07-22 16:05:57 -050069 // Attempt to find a routing table pool entry (RTPE) we can use.
Nick Gordonc0c6bcf2017-08-15 18:11:21 -050070 RoutingTableEntryPool::iterator rtpeItr = m_rtpool.find(destRouter);
Nick Gordonb50e51b2016-07-22 16:05:57 -050071
72 // These declarations just to make the compiler happy...
73 RoutingTablePoolEntry rtpe;
74 std::shared_ptr<RoutingTablePoolEntry> rtpePtr(nullptr);
75
76 // There isn't currently a routing table entry in the pool for this name
77 if (rtpeItr == m_rtpool.end()) {
78 // See if there is a routing table entry available we could use
79 RoutingTableEntry* routeEntryPtr = m_nlsr.getRoutingTable()
80 .findRoutingTableEntry(destRouter);
81
82 // We have to create a new routing table entry
83 if (routeEntryPtr == nullptr) {
84 rtpe = RoutingTablePoolEntry(destRouter, 0);
85 }
86 // There was already a usable one in the routing table
87 else {
88 rtpe = RoutingTablePoolEntry(*routeEntryPtr, 0);
89 }
90
91 // Add the new pool object to the pool.
92 rtpePtr = addRtpeToPool(rtpe);
93 }
94 // There was one already, so just fetch that one.
95 else {
96 rtpePtr = (*rtpeItr).second;
97 }
98
Nick Gordonc0c6bcf2017-08-15 18:11:21 -050099 std::shared_ptr<NamePrefixTableEntry> npte;
Nick Gordonb50e51b2016-07-22 16:05:57 -0500100 // Either we have to make a new NPT entry or there already was one.
101 if (nameItr == m_table.end()) {
102 _LOG_DEBUG("Adding origin: " << rtpePtr->getDestination()
103 << " to a new name prefix: " << name);
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500104 npte = make_shared<NamePrefixTableEntry>(name);
105 npte->addRoutingTableEntry(rtpePtr);
106 npte->generateNhlfromRteList();
Nick Gordonb50e51b2016-07-22 16:05:57 -0500107 m_table.push_back(npte);
Nick Gordonb50e51b2016-07-22 16:05:57 -0500108 // If this entry has next hops, we need to inform the FIB
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500109 if (npte->getNexthopList().getSize() > 0) {
Nick Gordonb50e51b2016-07-22 16:05:57 -0500110 _LOG_TRACE("Updating FIB with next hops for " << npte);
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500111 m_nlsr.getFib().update(name, npte->getNexthopList());
Nick Gordonb50e51b2016-07-22 16:05:57 -0500112 }
113 // The routing table may recalculate and add a routing table entry
114 // with no next hops to replace an existing routing table entry. In
115 // this case, the name prefix is no longer reachable through a next
116 // hop and should be removed from the FIB. But, the prefix should
117 // remain in the Name Prefix Table as a future routing table
118 // calculation may add next hops.
119 else {
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500120 _LOG_TRACE(*npte << " has no next hops; removing from FIB");
Nick Gordonb50e51b2016-07-22 16:05:57 -0500121 m_nlsr.getFib().remove(name);
122 }
akmhoque53353462014-04-22 08:43:45 -0500123 }
akmhoque157b0a42014-05-13 00:26:37 -0500124 else {
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500125 npte = *nameItr;
Nick Gordonb50e51b2016-07-22 16:05:57 -0500126 _LOG_TRACE("Adding origin: " << rtpePtr->getDestination()
127 << " to existing prefix: " << *nameItr);
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500128 (*nameItr)->addRoutingTableEntry(rtpePtr);
129 (*nameItr)->generateNhlfromRteList();
Nick Gordonb50e51b2016-07-22 16:05:57 -0500130
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500131 if ((*nameItr)->getNexthopList().getSize() > 0) {
Nick Gordonb50e51b2016-07-22 16:05:57 -0500132 _LOG_TRACE("Updating FIB with next hops for " << (*nameItr));
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500133 m_nlsr.getFib().update(name, (*nameItr)->getNexthopList());
Nick Gordonb50e51b2016-07-22 16:05:57 -0500134 }
135 else {
136 _LOG_TRACE((*nameItr) << " has no next hops; removing from FIB");
137 m_nlsr.getFib().remove(name);
138 }
akmhoque53353462014-04-22 08:43:45 -0500139 }
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500140 // Add the reference to this NPT to the RTPE.
141 rtpePtr->namePrefixTableEntries.emplace(
142 std::make_pair(npte->getNamePrefix(), std::weak_ptr<NamePrefixTableEntry>(npte)));
akmhoque53353462014-04-22 08:43:45 -0500143}
144
145void
akmhoque31d1d4b2014-05-05 22:08:14 -0500146NamePrefixTable::removeEntry(const ndn::Name& name, const ndn::Name& destRouter)
akmhoque53353462014-04-22 08:43:45 -0500147{
Vince Lehmancae33b62015-06-05 09:21:30 -0500148 _LOG_DEBUG("Removing origin: " << destRouter << " from " << name);
149
Nick Gordonb50e51b2016-07-22 16:05:57 -0500150 // Fetch an iterator to the appropriate pair object in the pool.
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500151 RoutingTableEntryPool::iterator rtpeItr = m_rtpool.find(destRouter);
Vince Lehmancae33b62015-06-05 09:21:30 -0500152
Nick Gordonb50e51b2016-07-22 16:05:57 -0500153 // Simple error checking to prevent any unusual behavior in the case
154 // that we try to remove an entry that isn't there.
155 if (rtpeItr == m_rtpool.end()) {
156 _LOG_DEBUG("No entry for origin: " << destRouter
157 << " found, so it cannot be removed from prefix: "
158 << name);
159 return;
160 }
161 std::shared_ptr<RoutingTablePoolEntry> rtpePtr = rtpeItr->second;
162
163 // Ensure that the entry exists
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500164 NptEntryList::iterator nameItr =
165 std::find_if(m_table.begin(), m_table.end(),
166 [&] (const std::shared_ptr<NamePrefixTableEntry>& entry) {
167 return entry->getNamePrefix() == name;
168 });
Nick Gordonb50e51b2016-07-22 16:05:57 -0500169 if (nameItr != m_table.end()) {
170 _LOG_TRACE("Removing origin: " << rtpePtr->getDestination()
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500171 << " from prefix: " << **nameItr);
Nick Gordonb50e51b2016-07-22 16:05:57 -0500172
173 // Rather than iterating through the whole list periodically, just
174 // delete them here if they have no references.
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500175 if ((*nameItr)->removeRoutingTableEntry(rtpePtr) == 0) {
Nick Gordonb50e51b2016-07-22 16:05:57 -0500176 deleteRtpeFromPool(rtpePtr);
177 }
178
179 // If the prefix is a router prefix and it does not have any other
180 // routing table entries, the Adjacency/Coordinate LSA associated
181 // with that origin router has been removed from the LSDB and so
182 // the router prefix should be removed from the Name Prefix Table.
183 //
184 // If the prefix is an advertised name prefix: If another router
185 // advertises this name prefix, the RteList should have another
186 // entry for that router; the next hops should be recalculated
187 // and installed in the FIB.
188 //
189 // If no other router advertises this name prefix, the RteList
190 // should be empty and the prefix can be removed from the Name
191 // Prefix Table. Once a new Name LSA advertises this prefix, a
192 // new entry for the prefix will be created.
193 //
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500194 if ((*nameItr)->getRteListSize() == 0) {
195 _LOG_TRACE(**nameItr << " has no routing table entries;"
Nick Gordonb50e51b2016-07-22 16:05:57 -0500196 << " removing from table and FIB");
197 m_table.erase(nameItr);
198 m_nlsr.getFib().remove(name);
199 }
200 else {
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500201 _LOG_TRACE(**nameItr << " has other routing table entries;"
Nick Gordonb50e51b2016-07-22 16:05:57 -0500202 << " updating FIB with next hops");
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500203 (*nameItr)->generateNhlfromRteList();
204 m_nlsr.getFib().update(name, (*nameItr)->getNexthopList());
Nick Gordonb50e51b2016-07-22 16:05:57 -0500205 }
akmhoque53353462014-04-22 08:43:45 -0500206 }
akmhoque157b0a42014-05-13 00:26:37 -0500207 else {
Nick Gordonb50e51b2016-07-22 16:05:57 -0500208 _LOG_DEBUG("Attempted to remove origin: " << rtpePtr->getDestination()
Ashlesh Gawande90173ad2017-08-09 15:19:50 -0500209 << " from non-existent prefix: " << name);
akmhoque53353462014-04-22 08:43:45 -0500210 }
211}
212
213void
Nick Gordonb7b58392017-08-17 16:29:21 -0500214NamePrefixTable::updateWithNewRoute(const std::list<RoutingTableEntry>& entries)
akmhoque53353462014-04-22 08:43:45 -0500215{
Vince Lehmancae33b62015-06-05 09:21:30 -0500216 _LOG_DEBUG("Updating table with newly calculated routes");
217
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500218 // Iterate over each pool entry we have
219 for (auto&& poolEntryPair : m_rtpool) {
220 auto&& poolEntry = poolEntryPair.second;
Nick Gordonb7b58392017-08-17 16:29:21 -0500221 auto sourceEntry = std::find_if(entries.begin(), entries.end(),
222 [&poolEntry] (const RoutingTableEntry& entry) {
223 return poolEntry->getDestination() == entry.getDestination();
224 });
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500225 // If this pool entry has a corresponding entry in the routing table now
Nick Gordonb7b58392017-08-17 16:29:21 -0500226 if (sourceEntry != entries.end()
227 && poolEntry->getNexthopList() != sourceEntry->getNexthopList()) {
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500228 _LOG_DEBUG("Routing entry: " << poolEntry->getDestination() << " has changed next-hops.");
229 poolEntry->setNexthopList(sourceEntry->getNexthopList());
230 for (const auto& nameEntry : poolEntry->namePrefixTableEntries) {
231 auto nameEntryFullPtr = nameEntry.second.lock();
232 addEntry(nameEntryFullPtr->getNamePrefix(), poolEntry->getDestination());
233 }
234 }
Nick Gordonb7b58392017-08-17 16:29:21 -0500235 else if (sourceEntry == entries.end()) {
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500236 _LOG_DEBUG("Routing entry: " << poolEntry->getDestination() << " now has no next-hops.");
237 poolEntry->getNexthopList().reset();
238 for (const auto& nameEntry : poolEntry->namePrefixTableEntries) {
239 auto nameEntryFullPtr = nameEntry.second.lock();
240 addEntry(nameEntryFullPtr->getNamePrefix(), poolEntry->getDestination());
241 }
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500242 }
243 else {
244 _LOG_TRACE("No change in routing entry:" << poolEntry->getDestination()
245 << ", no action necessary.");
akmhoque53353462014-04-22 08:43:45 -0500246 }
247 }
248}
249
Nick Gordonb50e51b2016-07-22 16:05:57 -0500250 // Inserts the routing table pool entry into the NPT's RTE storage
251 // pool. This cannot fail, so the pool is guaranteed to contain the
252 // item after this occurs.
253std::shared_ptr<RoutingTablePoolEntry>
254NamePrefixTable::addRtpeToPool(RoutingTablePoolEntry& rtpe)
255{
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500256 RoutingTableEntryPool::iterator poolItr =
Nick Gordonb50e51b2016-07-22 16:05:57 -0500257 m_rtpool.insert(std::make_pair(rtpe.getDestination(),
258 std::make_shared<RoutingTablePoolEntry>
259 (rtpe)))
260 .first;
Nick Gordonb50e51b2016-07-22 16:05:57 -0500261 return poolItr->second;
262}
263
264 // Removes the routing table pool entry from the storage pool. The
265 // postconditions of this function are guaranteed to include that
266 // the storage pool does not contain such an item. Additionally,
267 // this function cannot fail, but nonetheless debug information is
268 // given in the case that this function is called with an entry that
269 // isn't in the pool.
270void
271NamePrefixTable::deleteRtpeFromPool(std::shared_ptr<RoutingTablePoolEntry> rtpePtr)
272{
273 if (m_rtpool.erase(rtpePtr->getDestination()) != 1) {
Ashlesh Gawande90173ad2017-08-09 15:19:50 -0500274 _LOG_DEBUG("Attempted to delete non-existent origin: "
Nick Gordonb50e51b2016-07-22 16:05:57 -0500275 << rtpePtr->getDestination()
276 << " from NPT routing table entry storage pool.");
277 }
278}
279
akmhoque53353462014-04-22 08:43:45 -0500280void
akmhoque674b0b12014-05-20 14:33:28 -0500281NamePrefixTable::writeLog()
282{
Vince Lehmancae33b62015-06-05 09:21:30 -0500283 _LOG_DEBUG(*this);
akmhoque674b0b12014-05-20 14:33:28 -0500284}
285
Vince Lehmancae33b62015-06-05 09:21:30 -0500286std::ostream&
287operator<<(std::ostream& os, const NamePrefixTable& table)
288{
289 os << "----------------NPT----------------------\n";
290
Nick Gordonc0c6bcf2017-08-15 18:11:21 -0500291 for (const auto& entryPtr : table) {
292 os << *entryPtr << std::endl;
Vince Lehmancae33b62015-06-05 09:21:30 -0500293 }
294
295 return os;
296}
297
298} // namespace nlsr