name-prefix-table.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
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("NamePrefixTable");
35 
37  std::unique_ptr<AfterRoutingChange>& afterRoutingChangeSignal)
38  : m_nlsr(nlsr)
39 {
40  m_afterRoutingChangeConnection = afterRoutingChangeSignal->connect(
41  [this] (const std::list<RoutingTableEntry>& entries) {
42  updateWithNewRoute(entries);
43  });
44 }
45 
47 {
48  m_afterRoutingChangeConnection.disconnect();
49 }
50 
51 bool
52 npteCompare(std::shared_ptr<NamePrefixTableEntry>& npte, const ndn::Name& name)
53 {
54  return npte->getNamePrefix() == name;
55 }
56 
57 void
58 NamePrefixTable::addEntry(const ndn::Name& name, const ndn::Name& destRouter)
59 {
60 
61  // Check if the advertised name prefix is in the table already.
62  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  });
68 
69  // Attempt to find a routing table pool entry (RTPE) we can use.
70  RoutingTableEntryPool::iterator rtpeItr = m_rtpool.find(destRouter);
71 
72  // These declarations just to make the compiler happy...
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 
99  std::shared_ptr<NamePrefixTableEntry> npte;
100  // Either we have to make a new NPT entry or there already was one.
101  if (nameItr == m_table.end()) {
102  NLSR_LOG_DEBUG("Adding origin: " << rtpePtr->getDestination()
103  << " to a new name prefix: " << name);
104  npte = make_shared<NamePrefixTableEntry>(name);
105  npte->addRoutingTableEntry(rtpePtr);
106  npte->generateNhlfromRteList();
107  m_table.push_back(npte);
108  // If this entry has next hops, we need to inform the FIB
109  if (npte->getNexthopList().size() > 0) {
110  NLSR_LOG_TRACE("Updating FIB with next hops for " << npte);
111  m_nlsr.getFib().update(name, npte->getNexthopList());
112  }
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 {
120  NLSR_LOG_TRACE(*npte << " has no next hops; removing from FIB");
121  m_nlsr.getFib().remove(name);
122  }
123  }
124  else {
125  npte = *nameItr;
126  NLSR_LOG_TRACE("Adding origin: " << rtpePtr->getDestination()
127  << " to existing prefix: " << *nameItr);
128  (*nameItr)->addRoutingTableEntry(rtpePtr);
129  (*nameItr)->generateNhlfromRteList();
130 
131  if ((*nameItr)->getNexthopList().size() > 0) {
132  NLSR_LOG_TRACE("Updating FIB with next hops for " << (*nameItr));
133  m_nlsr.getFib().update(name, (*nameItr)->getNexthopList());
134  }
135  else {
136  NLSR_LOG_TRACE((*nameItr) << " has no next hops; removing from FIB");
137  m_nlsr.getFib().remove(name);
138  }
139  }
140  // Add the reference to this NPT to the RTPE.
141  rtpePtr->namePrefixTableEntries.emplace(
142  std::make_pair(npte->getNamePrefix(), std::weak_ptr<NamePrefixTableEntry>(npte)));
143 }
144 
145 void
146 NamePrefixTable::removeEntry(const ndn::Name& name, const ndn::Name& destRouter)
147 {
148  NLSR_LOG_DEBUG("Removing origin: " << destRouter << " from " << name);
149 
150  // Fetch an iterator to the appropriate pair object in the pool.
151  RoutingTableEntryPool::iterator rtpeItr = m_rtpool.find(destRouter);
152 
153  // 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  NLSR_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
164  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  });
169  if (nameItr != m_table.end()) {
170  NLSR_LOG_TRACE("Removing origin: " << rtpePtr->getDestination()
171  << " from prefix: " << **nameItr);
172 
173  // Rather than iterating through the whole list periodically, just
174  // delete them here if they have no references.
175  if ((*nameItr)->removeRoutingTableEntry(rtpePtr) == 0) {
176  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  //
194  if ((*nameItr)->getRteListSize() == 0) {
195  NLSR_LOG_TRACE(**nameItr << " has no routing table entries;"
196  << " removing from table and FIB");
197  m_table.erase(nameItr);
198  m_nlsr.getFib().remove(name);
199  }
200  else {
201  NLSR_LOG_TRACE(**nameItr << " has other routing table entries;"
202  << " updating FIB with next hops");
203  (*nameItr)->generateNhlfromRteList();
204  m_nlsr.getFib().update(name, (*nameItr)->getNexthopList());
205  }
206  }
207  else {
208  NLSR_LOG_DEBUG("Attempted to remove origin: " << rtpePtr->getDestination()
209  << " from non-existent prefix: " << name);
210  }
211 }
212 
213 void
214 NamePrefixTable::updateWithNewRoute(const std::list<RoutingTableEntry>& entries)
215 {
216  NLSR_LOG_DEBUG("Updating table with newly calculated routes");
217 
218  // Iterate over each pool entry we have
219  for (auto&& poolEntryPair : m_rtpool) {
220  auto&& poolEntry = poolEntryPair.second;
221  auto sourceEntry = std::find_if(entries.begin(), entries.end(),
222  [&poolEntry] (const RoutingTableEntry& entry) {
223  return poolEntry->getDestination() == entry.getDestination();
224  });
225  // If this pool entry has a corresponding entry in the routing table now
226  if (sourceEntry != entries.end()
227  && poolEntry->getNexthopList() != sourceEntry->getNexthopList()) {
228  NLSR_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  }
235  else if (sourceEntry == entries.end()) {
236  NLSR_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  }
242  }
243  else {
244  NLSR_LOG_TRACE("No change in routing entry:" << poolEntry->getDestination()
245  << ", no action necessary.");
246  }
247  }
248 }
249 
250  // 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.
253 std::shared_ptr<RoutingTablePoolEntry>
255 {
256  RoutingTableEntryPool::iterator poolItr =
257  m_rtpool.insert(std::make_pair(rtpe.getDestination(),
258  std::make_shared<RoutingTablePoolEntry>
259  (rtpe)))
260  .first;
261  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.
270 void
271 NamePrefixTable::deleteRtpeFromPool(std::shared_ptr<RoutingTablePoolEntry> rtpePtr)
272 {
273  if (m_rtpool.erase(rtpePtr->getDestination()) != 1) {
274  NLSR_LOG_DEBUG("Attempted to delete non-existent origin: "
275  << rtpePtr->getDestination()
276  << " from NPT routing table entry storage pool.");
277  }
278 }
279 
280 void
282 {
283  NLSR_LOG_DEBUG(*this);
284 }
285 
286 std::ostream&
287 operator<<(std::ostream& os, const NamePrefixTable& table)
288 {
289  os << "----------------NPT----------------------\n";
290 
291  for (const auto& entryPtr : table) {
292  os << *entryPtr << std::endl;
293  }
294 
295  return os;
296 }
297 
298 } // namespace nlsr
std::ostream & operator<<(std::ostream &os, const Adjacent &adjacent)
Definition: adjacent.cpp:83
std::shared_ptr< RoutingTablePoolEntry > addRtpeToPool(RoutingTablePoolEntry &rtpe)
Adds a pool entry to the pool.
void deleteRtpeFromPool(std::shared_ptr< RoutingTablePoolEntry > rtpePtr)
Removes a pool entry from the pool.
#define NLSR_LOG_DEBUG(x)
Definition: logger.hpp:41
RoutingTable & getRoutingTable()
Definition: nlsr.hpp:163
void updateWithNewRoute(const std::list< RoutingTableEntry > &entries)
Updates all routing information in the NPT.
Copyright (c) 2014-2017, The University of Memphis, Regents of the University of California.
#define INIT_LOGGER(name)
Definition: logger.hpp:35
void removeEntry(const ndn::Name &name, const ndn::Name &destRouter)
Removes a destination from a name prefix table entry.
const ndn::Name & getDestination() const
bool npteCompare(std::shared_ptr< NamePrefixTableEntry > &npte, const ndn::Name &name)
Copyright (c) 2014-2017, The University of Memphis, Regents of the University of California, Arizona Board of Regents.
void remove(const ndn::Name &name)
Completely remove a name prefix from the FIB.
Definition: fib.cpp:39
RoutingTableEntry * findRoutingTableEntry(const ndn::Name &destRouter)
void update(const ndn::Name &name, NexthopList &allHops)
Set the nexthop list of a name.
Definition: fib.cpp:79
Fib & getFib()
Definition: nlsr.hpp:175
#define NLSR_LOG_TRACE(x)
Definition: logger.hpp:38
NamePrefixTable(Nlsr &nlsr, std::unique_ptr< AfterRoutingChange > &afterRoutingChangeSignal)
void addEntry(const ndn::Name &name, const ndn::Name &destRouter)
Adds a destination to the specified name prefix.