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-2021, 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 
32 namespace nlsr {
33 
34 INIT_LOGGER(route.NamePrefixTable);
35 
37  std::unique_ptr<AfterRoutingChange>& afterRoutingChangeSignal)
38  : m_fib(fib)
39  , m_routingTable(routingTable)
40 {
41  m_afterRoutingChangeConnection = afterRoutingChangeSignal->connect(
42  [this] (const std::list<RoutingTableEntry>& entries) {
43  updateWithNewRoute(entries);
44  });
45 }
46 
48 {
49  m_afterRoutingChangeConnection.disconnect();
50 }
51 
52 void
53 NamePrefixTable::addEntry(const ndn::Name& name, const ndn::Name& destRouter)
54 {
55 
56  // Check if the advertised name prefix is in the table already.
57  NptEntryList::iterator nameItr =
58  std::find_if(m_table.begin(),
59  m_table.end(),
60  [&] (const std::shared_ptr<NamePrefixTableEntry>& entry) {
61  return name == entry->getNamePrefix();
62  });
63 
64  // Attempt to find a routing table pool entry (RTPE) we can use.
65  RoutingTableEntryPool::iterator rtpeItr = m_rtpool.find(destRouter);
66 
67  // These declarations just to make the compiler happy...
69  std::shared_ptr<RoutingTablePoolEntry> rtpePtr(nullptr);
70 
71  // There isn't currently a routing table entry in the pool for this name
72  if (rtpeItr == m_rtpool.end()) {
73  // See if there is a routing table entry available we could use
74  RoutingTableEntry* routeEntryPtr = m_routingTable.findRoutingTableEntry(destRouter);
75 
76  // We have to create a new routing table entry
77  if (routeEntryPtr == nullptr) {
78  rtpe = RoutingTablePoolEntry(destRouter, 0);
79  }
80  // There was already a usable one in the routing table
81  else {
82  rtpe = RoutingTablePoolEntry(*routeEntryPtr, 0);
83  }
84 
85  // Add the new pool object to the pool.
86  rtpePtr = addRtpeToPool(rtpe);
87  }
88  // There was one already, so just fetch that one.
89  else {
90  rtpePtr = (*rtpeItr).second;
91  }
92 
93  std::shared_ptr<NamePrefixTableEntry> npte;
94  // Either we have to make a new NPT entry or there already was one.
95  if (nameItr == m_table.end()) {
96  NLSR_LOG_DEBUG("Adding origin: " << rtpePtr->getDestination()
97  << " to a new name prefix: " << name);
98  npte = std::make_shared<NamePrefixTableEntry>(name);
99  npte->addRoutingTableEntry(rtpePtr);
100  npte->generateNhlfromRteList();
101  m_table.push_back(npte);
102 
103  // If this entry has next hops, we need to inform the FIB
104  if (npte->getNexthopList().size() > 0) {
105  NLSR_LOG_TRACE("Updating FIB with next hops for " << npte->getNamePrefix());
106  m_fib.update(name, npte->getNexthopList());
107  }
108  // The routing table may recalculate and add a routing table entry
109  // with no next hops to replace an existing routing table entry. In
110  // this case, the name prefix is no longer reachable through a next
111  // hop and should be removed from the FIB. But, the prefix should
112  // remain in the Name Prefix Table as a future routing table
113  // calculation may add next hops.
114  else {
115  NLSR_LOG_TRACE(npte->getNamePrefix() << " has no next hops; removing from FIB");
116  m_fib.remove(name);
117  }
118  }
119  else {
120  npte = *nameItr;
121  NLSR_LOG_TRACE("Adding origin: " << rtpePtr->getDestination() <<
122  " to existing prefix: " << **nameItr);
123  (*nameItr)->addRoutingTableEntry(rtpePtr);
124  (*nameItr)->generateNhlfromRteList();
125 
126  if ((*nameItr)->getNexthopList().size() > 0) {
127  NLSR_LOG_TRACE("Updating FIB with next hops for " << (**nameItr));
128  m_fib.update(name, (*nameItr)->getNexthopList());
129  }
130  else {
131  NLSR_LOG_TRACE(npte->getNamePrefix() << " has no next hops; removing from FIB");
132  m_fib.remove(name);
133  }
134  }
135 
136  // Add the reference to this NPT to the RTPE.
137  rtpePtr->namePrefixTableEntries.emplace(
138  std::make_pair(npte->getNamePrefix(), std::weak_ptr<NamePrefixTableEntry>(npte)));
139 }
140 
141 void
142 NamePrefixTable::removeEntry(const ndn::Name& name, const ndn::Name& destRouter)
143 {
144  NLSR_LOG_DEBUG("Removing origin: " << destRouter << " from " << name);
145 
146  // Fetch an iterator to the appropriate pair object in the pool.
147  RoutingTableEntryPool::iterator rtpeItr = m_rtpool.find(destRouter);
148 
149  // Simple error checking to prevent any unusual behavior in the case
150  // that we try to remove an entry that isn't there.
151  if (rtpeItr == m_rtpool.end()) {
152  NLSR_LOG_DEBUG("No entry for origin: " << destRouter
153  << " found, so it cannot be removed from prefix: "
154  << name);
155  return;
156  }
157  std::shared_ptr<RoutingTablePoolEntry> rtpePtr = rtpeItr->second;
158 
159  // Ensure that the entry exists
160  NptEntryList::iterator nameItr =
161  std::find_if(m_table.begin(), m_table.end(),
162  [&] (const std::shared_ptr<NamePrefixTableEntry>& entry) {
163  return entry->getNamePrefix() == name;
164  });
165  if (nameItr != m_table.end()) {
166  NLSR_LOG_TRACE("Removing origin: " << rtpePtr->getDestination()
167  << " from prefix: " << **nameItr);
168 
169  // Rather than iterating through the whole list periodically, just
170  // delete them here if they have no references.
171  if ((*nameItr)->removeRoutingTableEntry(rtpePtr) == 0) {
172  deleteRtpeFromPool(rtpePtr);
173  }
174 
175  // If the prefix is a router prefix and it does not have any other
176  // routing table entries, the Adjacency/Coordinate LSA associated
177  // with that origin router has been removed from the LSDB and so
178  // the router prefix should be removed from the Name Prefix Table.
179  //
180  // If the prefix is an advertised name prefix: If another router
181  // advertises this name prefix, the RteList should have another
182  // entry for that router; the next hops should be recalculated
183  // and installed in the FIB.
184  //
185  // If no other router advertises this name prefix, the RteList
186  // should be empty and the prefix can be removed from the Name
187  // Prefix Table. Once a new Name LSA advertises this prefix, a
188  // new entry for the prefix will be created.
189  //
190  if ((*nameItr)->getRteListSize() == 0) {
191  NLSR_LOG_TRACE(**nameItr << " has no routing table entries;"
192  << " removing from table and FIB");
193  m_table.erase(nameItr);
194  m_fib.remove(name);
195  }
196  else {
197  NLSR_LOG_TRACE(**nameItr << " has other routing table entries;"
198  << " updating FIB with next hops");
199  (*nameItr)->generateNhlfromRteList();
200  m_fib.update(name, (*nameItr)->getNexthopList());
201  }
202  }
203  else {
204  NLSR_LOG_DEBUG("Attempted to remove origin: " << rtpePtr->getDestination()
205  << " from non-existent prefix: " << name);
206  }
207 }
208 
209 void
210 NamePrefixTable::updateWithNewRoute(const std::list<RoutingTableEntry>& entries)
211 {
212  NLSR_LOG_DEBUG("Updating table with newly calculated routes");
213 
214  // Iterate over each pool entry we have
215  for (auto&& poolEntryPair : m_rtpool) {
216  auto&& poolEntry = poolEntryPair.second;
217  auto sourceEntry = std::find_if(entries.begin(), entries.end(),
218  [&poolEntry] (const RoutingTableEntry& entry) {
219  return poolEntry->getDestination() == entry.getDestination();
220  });
221  // If this pool entry has a corresponding entry in the routing table now
222  if (sourceEntry != entries.end()
223  && poolEntry->getNexthopList() != sourceEntry->getNexthopList()) {
224  NLSR_LOG_DEBUG("Routing entry: " << poolEntry->getDestination() << " has changed next-hops.");
225  poolEntry->setNexthopList(sourceEntry->getNexthopList());
226  for (const auto& nameEntry : poolEntry->namePrefixTableEntries) {
227  auto nameEntryFullPtr = nameEntry.second.lock();
228  addEntry(nameEntryFullPtr->getNamePrefix(), poolEntry->getDestination());
229  }
230  }
231  else if (sourceEntry == entries.end()) {
232  NLSR_LOG_DEBUG("Routing entry: " << poolEntry->getDestination() << " now has no next-hops.");
233  poolEntry->getNexthopList().clear();
234  for (const auto& nameEntry : poolEntry->namePrefixTableEntries) {
235  auto nameEntryFullPtr = nameEntry.second.lock();
236  addEntry(nameEntryFullPtr->getNamePrefix(), poolEntry->getDestination());
237  }
238  }
239  else {
240  NLSR_LOG_TRACE("No change in routing entry:" << poolEntry->getDestination()
241  << ", no action necessary.");
242  }
243  }
244 }
245 
246  // Inserts the routing table pool entry into the NPT's RTE storage
247  // pool. This cannot fail, so the pool is guaranteed to contain the
248  // item after this occurs.
249 std::shared_ptr<RoutingTablePoolEntry>
251 {
252  RoutingTableEntryPool::iterator poolItr =
253  m_rtpool.insert(std::make_pair(rtpe.getDestination(),
254  std::make_shared<RoutingTablePoolEntry>
255  (rtpe)))
256  .first;
257  return poolItr->second;
258 }
259 
260  // Removes the routing table pool entry from the storage pool. The
261  // postconditions of this function are guaranteed to include that
262  // the storage pool does not contain such an item. Additionally,
263  // this function cannot fail, but nonetheless debug information is
264  // given in the case that this function is called with an entry that
265  // isn't in the pool.
266 void
267 NamePrefixTable::deleteRtpeFromPool(std::shared_ptr<RoutingTablePoolEntry> rtpePtr)
268 {
269  if (m_rtpool.erase(rtpePtr->getDestination()) != 1) {
270  NLSR_LOG_DEBUG("Attempted to delete non-existent origin: "
271  << rtpePtr->getDestination()
272  << " from NPT routing table entry storage pool.");
273  }
274 }
275 
276 void
278 {
279  NLSR_LOG_DEBUG(*this);
280 }
281 
282 std::ostream&
283 operator<<(std::ostream& os, const NamePrefixTable& table)
284 {
285  os << "----------------NPT----------------------\n";
286 
287  for (const auto& entryPtr : table) {
288  os << *entryPtr << std::endl;
289  }
290 
291  return os;
292 }
293 
294 } // namespace nlsr
Maps names to lists of next hops, and exports this information to NFD.
Definition: fib.hpp:60
void remove(const ndn::Name &name)
Completely remove a name prefix from the FIB.
Definition: fib.cpp:50
void update(const ndn::Name &name, const NexthopList &allHops)
Set the nexthop list of a name.
Definition: fib.cpp:87
std::shared_ptr< RoutingTablePoolEntry > addRtpeToPool(RoutingTablePoolEntry &rtpe)
Adds a pool entry to the pool.
void removeEntry(const ndn::Name &name, const ndn::Name &destRouter)
Removes a destination from a name prefix table entry.
NamePrefixTable(Fib &fib, RoutingTable &routingTable, std::unique_ptr< AfterRoutingChange > &afterRoutingChangeSignal)
void updateWithNewRoute(const std::list< RoutingTableEntry > &entries)
Updates all routing information in the NPT.
void addEntry(const ndn::Name &name, const ndn::Name &destRouter)
Adds a destination to the specified name prefix.
void deleteRtpeFromPool(std::shared_ptr< RoutingTablePoolEntry > rtpePtr)
Removes a pool entry from the pool.
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:179