Loading...
Searching...
No Matches
name-prefix-table.cpp
Go to the documentation of this file.
1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2014-2025, The University of Memphis,
4 * Regents of the University of California,
5 * Arizona Board of Regents.
6 *
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/>.
20 */
21
22#include "name-prefix-table.hpp"
23
24#include "logger.hpp"
25#include "nlsr.hpp"
26#include "routing-table.hpp"
27
28#include <algorithm>
29#include <list>
30#include <utility>
31
32namespace nlsr {
33
34INIT_LOGGER(route.NamePrefixTable);
35
36NamePrefixTable::NamePrefixTable(const ndn::Name& ownRouterName, Fib& fib,
37 RoutingTable& routingTable,
38 AfterRoutingChange& afterRoutingChangeSignal,
39 Lsdb::AfterLsdbModified& afterLsdbModifiedSignal)
40 : m_ownRouterName(ownRouterName)
41 , m_fib(fib)
42 , m_routingTable(routingTable)
43{
44 m_afterRoutingChangeConnection = afterRoutingChangeSignal.connect(
45 [this] (const std::list<RoutingTableEntry>& entries) {
46 updateWithNewRoute(entries);
47 });
48
49 m_afterLsdbModified = afterLsdbModifiedSignal.connect(
50 [this] (std::shared_ptr<Lsa> lsa, LsdbUpdate updateType,
51 const auto& namesToAdd, const auto& namesToRemove) {
52 updateFromLsdb(lsa, updateType, namesToAdd, namesToRemove);
53 }
54 );
55}
56
58{
59 m_afterRoutingChangeConnection.disconnect();
60 m_afterLsdbModified.disconnect();
61}
62
63void
64NamePrefixTable::updateFromLsdb(std::shared_ptr<Lsa> lsa, LsdbUpdate updateType,
65 const std::list<nlsr::PrefixInfo>& namesToAdd,
66 const std::list<nlsr::PrefixInfo>& namesToRemove)
67{
68 if (m_ownRouterName == lsa->getOriginRouter()) {
69 return;
70 }
71 NLSR_LOG_TRACE("Got update from Lsdb for router: " << lsa->getOriginRouter());
72
73 if (updateType == LsdbUpdate::INSTALLED) {
74 addEntry(lsa->getOriginRouter(), lsa->getOriginRouter());
75
76 if (lsa->getType() == Lsa::Type::NAME) {
77 auto nlsa = std::static_pointer_cast<NameLsa>(lsa);
78 for (const auto &prefix : nlsa->getNpl().getPrefixInfo()) {
79 if (prefix.getName() != m_ownRouterName) {
80 m_nexthopCost[DestNameKey(lsa->getOriginRouter(), prefix.getName())] = prefix.getCost();
81 // Don't use capture flag on advertised prefixes...
82 addEntry(prefix.getName(), lsa->getOriginRouter(), ndn::nfd::ROUTE_FLAG_CHILD_INHERIT);
83 }
84 }
85 }
86 }
87 else if (updateType == LsdbUpdate::UPDATED) {
88 if (lsa->getType() != Lsa::Type::NAME) {
89 return;
90 }
91
92 for (const auto &prefix : namesToAdd) {
93 if (prefix.getName() != m_ownRouterName) {
94 m_nexthopCost[DestNameKey(lsa->getOriginRouter(), prefix.getName())] = prefix.getCost();
95 // Don't use capture flag on advertised prefixes...
96 addEntry(prefix.getName(), lsa->getOriginRouter(), ndn::nfd::ROUTE_FLAG_CHILD_INHERIT);
97 }
98 }
99
100 for (const auto &prefix : namesToRemove) {
101 if (prefix.getName() != m_ownRouterName) {
102 m_nexthopCost.erase(m_nexthopCost.find(DestNameKey(lsa->getOriginRouter(), prefix.getName())));
103 removeEntry(prefix.getName(), lsa->getOriginRouter());
104 }
105 }
106 }
107 else {
108 removeEntry(lsa->getOriginRouter(), lsa->getOriginRouter());
109 if (lsa->getType() == Lsa::Type::NAME) {
110 auto nlsa = std::static_pointer_cast<NameLsa>(lsa);
111 for (const auto& name : nlsa->getNpl().getNames()) {
112 if (name != m_ownRouterName) {
113 m_nexthopCost.erase(m_nexthopCost.find(DestNameKey(lsa->getOriginRouter(), name)));
114 removeEntry(name, lsa->getOriginRouter());
115 }
116 }
117 }
118 }
119}
120
122NamePrefixTable::adjustNexthopCosts(const NexthopList& nhlist, const ndn::Name& nameToCheck, const ndn::Name& destRouterName)
123{
124 NexthopList new_nhList;
125 for (const auto& nh : nhlist.getNextHops()) {
126 const NextHop newNextHop = NextHop(nh.getConnectingFaceUri(), nh.getRouteCost() +
127 m_nexthopCost[DestNameKey(destRouterName, nameToCheck)]);
128 new_nhList.addNextHop(newNextHop);
129 }
130 return new_nhList;
131}
132
133void
134NamePrefixTable::addEntry(const ndn::Name& name, const ndn::Name& destRouter, uint64_t routeFlags)
135{
136 // Check if the advertised name prefix is in the table already.
137 auto nameItr = std::find_if(m_table.begin(), m_table.end(),
138 [&] (const auto& entry) { return name == entry->getNamePrefix(); });
139
140 // Attempt to find a routing table pool entry (RTPE) we can use.
141 auto rtpeItr = m_rtpool.find(destRouter);
142
143 // These declarations just to make the compiler happy...
145 std::shared_ptr<RoutingTablePoolEntry> rtpePtr(nullptr);
146
147 // There isn't currently a routing table entry in the pool for this name
148 if (rtpeItr == m_rtpool.end()) {
149 // See if there is a routing table entry available we could use
150 RoutingTableEntry* routeEntryPtr = m_routingTable.findRoutingTableEntry(destRouter);
151
152 // We have to create a new routing table entry
153 if (routeEntryPtr == nullptr) {
154 rtpe = RoutingTablePoolEntry(destRouter, 0);
155 }
156 // There was already a usable one in the routing table
157 else {
158 rtpe = RoutingTablePoolEntry(*routeEntryPtr, 0);
159 }
160
161 // Add the new pool object to the pool.
162 rtpePtr = addRtpeToPool(rtpe);
163 }
164 // There was one already, so just fetch that one.
165 else {
166 rtpePtr = (*rtpeItr).second;
167 }
168
169 std::shared_ptr<NamePrefixTableEntry> npte;
170 // Either we have to make a new NPT entry or there already was one.
171 if (nameItr == m_table.end()) {
172 NLSR_LOG_DEBUG("Adding origin: " << rtpePtr->getDestination()
173 << " to a new name prefix: " << name);
174
175 npte = std::make_shared<NamePrefixTableEntry>(name, ndn::nfd::ROUTE_FLAG_CHILD_INHERIT);
176 npte->addRoutingTableEntry(rtpePtr);
177 npte->generateNhlfromRteList();
178 m_table.push_back(npte);
179
180 // If this entry has next hops, we need to inform the FIB
181 if (npte->getNexthopList().size() > 0) {
182 NLSR_LOG_TRACE("Updating FIB with next hops for " << npte->getNamePrefix());
183 m_fib.update(name, adjustNexthopCosts(npte->getNexthopList(), name, destRouter), npte->getFlags());
184 }
185 // The routing table may recalculate and add a routing table entry
186 // with no next hops to replace an existing routing table entry. In
187 // this case, the name prefix is no longer reachable through a next
188 // hop and should be removed from the FIB. But, the prefix should
189 // remain in the Name Prefix Table as a future routing table
190 // calculation may add next hops.
191 else {
192 NLSR_LOG_TRACE(npte->getNamePrefix() << " has no next hops; removing from FIB");
193 m_fib.remove(name);
194 }
195 }
196 else {
197 npte = *nameItr;
198 NLSR_LOG_TRACE("Adding origin: " << rtpePtr->getDestination() <<
199 " to existing prefix: " << *npte);
200 // We should not downgrade the capture flag to child-inherit unless there are no nexthops
201 if (npte->getFlags() != routeFlags && npte->getNexthopList().size() == 0) {
202 npte->setFlags(routeFlags);
203 }
204 npte->addRoutingTableEntry(rtpePtr);
205 npte->generateNhlfromRteList();
206 if (npte->getNexthopList().size() > 0) {
207 NLSR_LOG_TRACE("Updating FIB with next hops for " << *npte);
208 m_fib.update(name, adjustNexthopCosts(npte->getNexthopList(), name, destRouter), npte->getFlags());
209 }
210 else {
211 NLSR_LOG_TRACE(npte->getNamePrefix() << " has no next hops; removing from FIB");
212 m_fib.remove(name);
213 }
214 }
215
216 // Add the reference to this NPT to the RTPE.
217 rtpePtr->namePrefixTableEntries.try_emplace(npte->getNamePrefix(),
218 std::weak_ptr<NamePrefixTableEntry>(npte));
219}
220
221void
222NamePrefixTable::removeEntry(const ndn::Name& name, const ndn::Name& destRouter)
223{
224 NLSR_LOG_DEBUG("Removing origin: " << destRouter << " from " << name);
225
226 // Fetch an iterator to the appropriate pair object in the pool.
227 auto rtpeItr = m_rtpool.find(destRouter);
228
229 // Simple error checking to prevent any unusual behavior in the case
230 // that we try to remove an entry that isn't there.
231 if (rtpeItr == m_rtpool.end()) {
232 NLSR_LOG_DEBUG("No entry for origin: " << destRouter
233 << " found, so it cannot be removed from prefix: " << name);
234 return;
235 }
236 std::shared_ptr<RoutingTablePoolEntry> rtpePtr = rtpeItr->second;
237
238 // Ensure that the entry exists
239 auto nameItr = std::find_if(m_table.begin(), m_table.end(),
240 [&] (const auto& entry) { return entry->getNamePrefix() == name; });
241 if (nameItr != m_table.end()) {
242 std::shared_ptr<NamePrefixTableEntry> npte = *nameItr;
243 NLSR_LOG_TRACE("Removing origin: " << rtpePtr->getDestination()
244 << " from prefix: " << **nameItr);
245
246 // Rather than iterating through the whole list periodically, just
247 // delete them here if they have no references.
248 if (npte->removeRoutingTableEntry(rtpePtr) == 0) {
249 deleteRtpeFromPool(rtpePtr);
250 }
251
252 // If the prefix is a router prefix and it does not have any other
253 // routing table entries, the Adjacency/Coordinate LSA associated
254 // with that origin router has been removed from the LSDB and so
255 // the router prefix should be removed from the Name Prefix Table.
256 //
257 // If the prefix is an advertised name prefix: If another router
258 // advertises this name prefix, the RteList should have another
259 // entry for that router; the next hops should be recalculated
260 // and installed in the FIB.
261 //
262 // If no other router advertises this name prefix, the RteList
263 // should be empty and the prefix can be removed from the Name
264 // Prefix Table. Once a new Name LSA advertises this prefix, a
265 // new entry for the prefix will be created.
266 //
267 if (npte->getRteListSize() == 0) {
268 NLSR_LOG_TRACE(*npte << " has no routing table entries;"
269 << " removing from table and FIB");
270 m_table.erase(nameItr);
271 m_fib.remove(name);
272 }
273 else {
274 NLSR_LOG_TRACE(*npte << " has other routing table entries;"
275 << " updating FIB with next hops");
276 (*nameItr)->generateNhlfromRteList();
277 m_fib.update(name, adjustNexthopCosts(npte->getNexthopList(), name, destRouter), npte->getFlags());
278 }
279 }
280 else {
281 NLSR_LOG_DEBUG("Attempted to remove origin: " << rtpePtr->getDestination()
282 << " from non-existent prefix: " << name);
283 }
284}
285
286void
287NamePrefixTable::updateWithNewRoute(const std::list<RoutingTableEntry>& entries)
288{
289 NLSR_LOG_DEBUG("Updating table with newly calculated routes");
290
291 // Iterate over each pool entry we have
292 for (auto&& poolEntryPair : m_rtpool) {
293 auto&& poolEntry = poolEntryPair.second;
294 auto sourceEntry = std::find_if(entries.begin(), entries.end(),
295 [&poolEntry] (const RoutingTableEntry& entry) {
296 return poolEntry->getDestination() == entry.getDestination();
297 });
298 // If this pool entry has a corresponding entry in the routing table now
299 if (sourceEntry != entries.end()
300 && poolEntry->getNexthopList() != sourceEntry->getNexthopList()) {
301 NLSR_LOG_DEBUG("Routing entry: " << poolEntry->getDestination() << " has changed next-hops.");
302 poolEntry->setNexthopList(sourceEntry->getNexthopList());
303 for (const auto& nameEntry : poolEntry->namePrefixTableEntries) {
304 auto nameEntryFullPtr = nameEntry.second.lock();
305 addEntry(nameEntryFullPtr->getNamePrefix(), poolEntry->getDestination(), nameEntryFullPtr->getFlags());
306 }
307 }
308 else if (sourceEntry == entries.end()) {
309 NLSR_LOG_DEBUG("Routing entry: " << poolEntry->getDestination() << " now has no next-hops.");
310 poolEntry->getNexthopList().clear();
311 for (const auto& nameEntry : poolEntry->namePrefixTableEntries) {
312 auto nameEntryFullPtr = nameEntry.second.lock();
313 addEntry(nameEntryFullPtr->getNamePrefix(), poolEntry->getDestination(), nameEntryFullPtr->getFlags());
314 }
315 }
316 else {
317 NLSR_LOG_TRACE("No change in routing entry:" << poolEntry->getDestination()
318 << ", no action necessary.");
319 }
320 }
321}
322
323// Inserts the routing table pool entry into the NPT's RTE storage
324// pool. This cannot fail, so the pool is guaranteed to contain the
325// item after this occurs.
326std::shared_ptr<RoutingTablePoolEntry>
328{
329 auto poolIt = m_rtpool.try_emplace(rtpe.getDestination(),
330 std::make_shared<RoutingTablePoolEntry>(rtpe)).first;
331 return poolIt->second;
332}
333
334// Removes the routing table pool entry from the storage pool. The
335// postconditions of this function are guaranteed to include that
336// the storage pool does not contain such an item. Additionally,
337// this function cannot fail, but nonetheless debug information is
338// given in the case that this function is called with an entry that
339// isn't in the pool.
340void
341NamePrefixTable::deleteRtpeFromPool(std::shared_ptr<RoutingTablePoolEntry> rtpePtr)
342{
343 if (m_rtpool.erase(rtpePtr->getDestination()) != 1) {
344 NLSR_LOG_DEBUG("Attempted to delete non-existent origin: "
345 << rtpePtr->getDestination()
346 << " from NPT routing table entry storage pool.");
347 }
348}
349
350void
355
356std::ostream&
357operator<<(std::ostream& os, const NamePrefixTable& table)
358{
359 os << "----------------NPT----------------------\n";
360
361 for (const auto& entryPtr : table) {
362 os << *entryPtr << std::endl;
363 }
364
365 return os;
366}
367
368} // namespace nlsr
Maps names to lists of next hops, and exports this information to NFD.
Definition fib.hpp:63
void remove(const ndn::Name &name)
Completely remove a name prefix from the FIB.
Definition fib.cpp:48
void update(const ndn::Name &name, const NexthopList &allHops, uint64_t routeFlags)
Set the nexthop list of a name.
Definition fib.cpp:86
ndn::signal::Signal< Lsdb, std::shared_ptr< Lsa >, LsdbUpdate, std::list< nlsr::PrefixInfo >, std::list< nlsr::PrefixInfo > > AfterLsdbModified
Definition lsdb.hpp:338
std::shared_ptr< RoutingTablePoolEntry > addRtpeToPool(RoutingTablePoolEntry &rtpe)
Adds a pool entry to the pool.
void addEntry(const ndn::Name &name, const ndn::Name &destRouter, uint64_t routeFlags=ndn::nfd::ROUTE_FLAG_CAPTURE)
Adds a destination to the specified name prefix.
void removeEntry(const ndn::Name &name, const ndn::Name &destRouter)
Removes a destination from a name prefix table entry.
void updateFromLsdb(std::shared_ptr< Lsa > lsa, LsdbUpdate updateType, const std::list< nlsr::PrefixInfo > &namesToAdd, const std::list< nlsr::PrefixInfo > &namesToRemove)
Add, update, or remove Names according to the Lsdb update.
void updateWithNewRoute(const std::list< RoutingTableEntry > &entries)
Updates all routing information in the NPT.
std::tuple< ndn::Name, ndn::Name > DestNameKey
NexthopList adjustNexthopCosts(const NexthopList &nhlist, const ndn::Name &nameToCheck, const ndn::Name &destRouterName)
NamePrefixTable(const ndn::Name &ownRouterName, Fib &fib, RoutingTable &routingTable, AfterRoutingChange &afterRoutingChangeSignal, Lsdb::AfterLsdbModified &afterLsdbModifiedSignal)
void deleteRtpeFromPool(std::shared_ptr< RoutingTablePoolEntry > rtpePtr)
Removes a pool entry from the pool.
Data abstraction for Nexthop.
Definition nexthop.hpp:47
const std::set< NextHop, T > & getNextHops() const
void addNextHop(const NextHop &nh)
Adds a next hop to the list.
Data abstraction for RouteTableInfo.
const ndn::Name & getDestination() const
RoutingTableEntry * findRoutingTableEntry(const ndn::Name &destRouter)
Copyright (c) 2014-2018, The University of Memphis, Regents of the University of California.
#define NLSR_LOG_DEBUG(x)
Definition logger.hpp:38
#define INIT_LOGGER(name)
Definition logger.hpp:35
#define NLSR_LOG_TRACE(x)
Definition logger.hpp:37
Copyright (c) 2014-2020, The University of Memphis, Regents of the University of California.
std::ostream & operator<<(std::ostream &os, const Adjacent &adjacent)
Definition adjacent.cpp:176
ndn::signal::Signal< RoutingTable, std::list< RoutingTableEntry > > AfterRoutingChange
Definition signals.hpp:35
LsdbUpdate
Definition lsdb.hpp:53