BREAKING: Change Name LSAs to propagate cost which are applied to remote routes

This is a stopgap change to address a lack of functionality in the NDN testbed.
Current restrictions:
-Cost must be set from NFD readvertisement
-Cost is applied after routing calculations but before FIB insertion; lowest cost
nexthop will be chosen but may not be the optimal path given this cost.

Further work will be required to move the application of cost as part of routing
and to make this functionality more easily accessible.

Refs #5349

Change-Id: I914dc5c2d5d3cb6bfa13f5730df0eae66d115c60
diff --git a/docs/manpages/nlsrc.rst b/docs/manpages/nlsrc.rst
index 7b566b4..d93280d 100644
--- a/docs/manpages/nlsrc.rst
+++ b/docs/manpages/nlsrc.rst
@@ -84,6 +84,9 @@
 
   ndnsec set-default /ndn/a-site/%C1.Operator/op
 
+Support for adding prefix costs is currently only implemented via readvertisement;
+this functionality will be added in a future release.
+
 Exit Status
 -----------
 
diff --git a/src/lsa/adj-lsa.cpp b/src/lsa/adj-lsa.cpp
index f143499..9b58098 100644
--- a/src/lsa/adj-lsa.cpp
+++ b/src/lsa/adj-lsa.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2024,  The University of Memphis,
+ * Copyright (c) 2014-2025,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -126,7 +126,7 @@
   }
 }
 
-std::tuple<bool, std::list<ndn::Name>, std::list<ndn::Name>>
+std::tuple<bool, std::list<PrefixInfo>, std::list<PrefixInfo>>
 AdjLsa::update(const std::shared_ptr<Lsa>& lsa)
 {
   auto alsa = std::static_pointer_cast<AdjLsa>(lsa);
@@ -135,9 +135,9 @@
     for (const auto& adjacent : alsa->getAdl()) {
       addAdjacent(adjacent);
     }
-    return {true, std::list<ndn::Name>{}, std::list<ndn::Name>{}};
+    return {true, std::list<PrefixInfo>{}, std::list<PrefixInfo>{}};
   }
-  return {false, std::list<ndn::Name>{}, std::list<ndn::Name>{}};
+  return {false, std::list<PrefixInfo>{}, std::list<PrefixInfo>{}};
 }
 
 } // namespace nlsr
diff --git a/src/lsa/adj-lsa.hpp b/src/lsa/adj-lsa.hpp
index 8c6354d..5fc3903 100644
--- a/src/lsa/adj-lsa.hpp
+++ b/src/lsa/adj-lsa.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2024,  The University of Memphis,
+ * Copyright (c) 2014-2025,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -107,7 +107,7 @@
   void
   wireDecode(const ndn::Block& wire);
 
-  std::tuple<bool, std::list<ndn::Name>, std::list<ndn::Name>>
+  std::tuple<bool, std::list<PrefixInfo>, std::list<PrefixInfo>>
   update(const std::shared_ptr<Lsa>& lsa) override;
 
 private:
diff --git a/src/lsa/coordinate-lsa.cpp b/src/lsa/coordinate-lsa.cpp
index 11428f8..3008915 100644
--- a/src/lsa/coordinate-lsa.cpp
+++ b/src/lsa/coordinate-lsa.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2024,  The University of Memphis,
+ * Copyright (c) 2014-2025,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -129,7 +129,7 @@
   }
 }
 
-std::tuple<bool, std::list<ndn::Name>, std::list<ndn::Name>>
+std::tuple<bool, std::list<PrefixInfo>, std::list<PrefixInfo>>
 CoordinateLsa::update(const std::shared_ptr<Lsa>& lsa)
 {
   auto clsa = std::static_pointer_cast<CoordinateLsa>(lsa);
@@ -139,9 +139,9 @@
     for (const auto& angle : clsa->getTheta()) {
       m_hyperbolicAngles.push_back(angle);
     }
-    return {true, std::list<ndn::Name>{}, std::list<ndn::Name>{}};
+    return {true, std::list<PrefixInfo>{}, std::list<PrefixInfo>{}};
   }
-  return {false, std::list<ndn::Name>{}, std::list<ndn::Name>{}};
+  return {false, std::list<PrefixInfo>{}, std::list<PrefixInfo>{}};
 }
 
 } // namespace nlsr
diff --git a/src/lsa/coordinate-lsa.hpp b/src/lsa/coordinate-lsa.hpp
index 3e7f0a1..60ef965 100644
--- a/src/lsa/coordinate-lsa.hpp
+++ b/src/lsa/coordinate-lsa.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2024,  The University of Memphis,
+ * Copyright (c) 2014-2025,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -106,7 +106,7 @@
   void
   wireDecode(const ndn::Block& wire);
 
-  std::tuple<bool, std::list<ndn::Name>, std::list<ndn::Name>>
+  std::tuple<bool, std::list<PrefixInfo>, std::list<PrefixInfo>>
   update(const std::shared_ptr<Lsa>& lsa) override;
 
 private:
diff --git a/src/lsa/lsa.hpp b/src/lsa/lsa.hpp
index e482a92..a52a4f7 100644
--- a/src/lsa/lsa.hpp
+++ b/src/lsa/lsa.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2024,  The University of Memphis,
+ * Copyright (c) 2014-2025,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -23,12 +23,14 @@
 #define NLSR_LSA_LSA_HPP
 
 #include "common.hpp"
+#include "name-prefix-list.hpp"
 #include "test-access-control.hpp"
 
 #include <ndn-cxx/util/scheduler.hpp>
 
 #include <list>
 
+
 namespace nlsr {
 
 /**
@@ -112,7 +114,7 @@
     m_expiringEventId = eid;
   }
 
-  virtual std::tuple<bool, std::list<ndn::Name>, std::list<ndn::Name>>
+  virtual std::tuple<bool, std::list<PrefixInfo>, std::list<PrefixInfo>>
   update(const std::shared_ptr<Lsa>& lsa) = 0;
 
   virtual const ndn::Block&
diff --git a/src/lsa/name-lsa.cpp b/src/lsa/name-lsa.cpp
index 7867b68..2efe86e 100644
--- a/src/lsa/name-lsa.cpp
+++ b/src/lsa/name-lsa.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2024,  The University of Memphis,
+ * Copyright (c) 2014-2025,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -29,7 +29,7 @@
                  const NamePrefixList& npl)
   : Lsa(originRouter, seqNo, timepoint)
 {
-  for (const auto& name : npl.getNames()) {
+  for (const auto& name : npl.getPrefixInfo()) {
     addName(name);
   }
 }
@@ -45,7 +45,7 @@
 {
   size_t totalLength = 0;
 
-  auto names = m_npl.getNames();
+  auto names = m_npl.getPrefixInfo();
 
   for (auto it = names.rbegin();  it != names.rend(); ++it) {
     totalLength += it->wireEncode(block);
@@ -102,8 +102,9 @@
 
   NamePrefixList npl;
   for (; val != m_wire.elements_end(); ++val) {
-    if (val->type() == ndn::tlv::Name) {
-      npl.insert(ndn::Name(*val));
+    if (val->type() == nlsr::tlv::PrefixInfo) {
+      //TODO: Implement this structure as a type instead and add decoding
+      npl.insert(PrefixInfo(*val));
     }
     else {
       NDN_THROW(Error("Name", val->type()));
@@ -117,12 +118,14 @@
 {
   os << "      Names:\n";
   int i = 0;
-  for (const auto& name : m_npl.getNames()) {
-    os << "        Name " << i++ << ": " << name << "\n";
+  for (const auto& name : m_npl.getPrefixInfo()) {
+    os << "        Name " << i << ": " << name.getName()
+       << " | Cost: " << name.getCost() << "\n";
+    i++;
   }
 }
 
-std::tuple<bool, std::list<ndn::Name>, std::list<ndn::Name>>
+std::tuple<bool, std::list<PrefixInfo>, std::list<PrefixInfo>>
 NameLsa::update(const std::shared_ptr<Lsa>& lsa)
 {
   auto nlsa = std::static_pointer_cast<NameLsa>(lsa);
@@ -130,25 +133,31 @@
 
   // Obtain the set difference of the current and the incoming
   // name prefix sets, and add those.
+
   std::list<ndn::Name> newNames = nlsa->getNpl().getNames();
   std::list<ndn::Name> oldNames = m_npl.getNames();
-  std::list<ndn::Name> namesToAdd;
+  std::list<ndn::Name> nameRefToAdd;
+  std::list<PrefixInfo> namesToAdd;
+
   std::set_difference(newNames.begin(), newNames.end(), oldNames.begin(), oldNames.end(),
-                      std::inserter(namesToAdd, namesToAdd.begin()));
-  for (const auto& name : namesToAdd) {
-    addName(name);
+                      std::inserter(nameRefToAdd, nameRefToAdd.begin()));
+  for (const auto& name : nameRefToAdd) {
+    namesToAdd.push_back(nlsa->getNpl().getPrefixInfoForName(name));
+    addName(nlsa->getNpl().getPrefixInfoForName(name));
     updated = true;
   }
 
   // Also remove any names that are no longer being advertised.
-  std::list<ndn::Name> namesToRemove;
+  std::list<ndn::Name> nameRefToRemove;
+  std::list<PrefixInfo> namesToRemove;
   std::set_difference(oldNames.begin(), oldNames.end(), newNames.begin(), newNames.end(),
-                      std::inserter(namesToRemove, namesToRemove.begin()));
-  for (const auto& name : namesToRemove) {
-    removeName(name);
+                      std::inserter(nameRefToRemove, nameRefToRemove.begin()));
+  for (const auto& name : nameRefToRemove) {
+    namesToRemove.push_back(m_npl.getPrefixInfoForName(name));
+    removeName(m_npl.getPrefixInfoForName(name));
+
     updated = true;
   }
-
   return {updated, namesToAdd, namesToRemove};
 }
 
diff --git a/src/lsa/name-lsa.hpp b/src/lsa/name-lsa.hpp
index 625bbb7..27f46b1 100644
--- a/src/lsa/name-lsa.hpp
+++ b/src/lsa/name-lsa.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2024,  The University of Memphis,
+ * Copyright (c) 2014-2025,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -76,17 +76,17 @@
   }
 
   void
-  addName(const ndn::Name& name)
+  addName(const PrefixInfo& name)
   {
     m_wire.reset();
     m_npl.insert(name);
   }
 
   void
-  removeName(const ndn::Name& name)
+  removeName(const PrefixInfo& name)
   {
     m_wire.reset();
-    m_npl.erase(name);
+    m_npl.erase(name.getName());
   }
 
   template<ndn::encoding::Tag TAG>
@@ -99,7 +99,7 @@
   void
   wireDecode(const ndn::Block& wire);
 
-  std::tuple<bool, std::list<ndn::Name>, std::list<ndn::Name>>
+  std::tuple<bool, std::list<PrefixInfo>, std::list<PrefixInfo>>
   update(const std::shared_ptr<Lsa>& lsa) override;
 
 private:
diff --git a/src/lsdb.hpp b/src/lsdb.hpp
index 7e1d9ad..ba7052d 100644
--- a/src/lsdb.hpp
+++ b/src/lsdb.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2024,  The University of Memphis,
+ * Copyright (c) 2014-2025,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -335,7 +335,7 @@
   ndn::signal::Signal<Lsdb, Statistics::PacketType> lsaIncrementSignal;
   ndn::signal::Signal<Lsdb, ndn::Data> afterSegmentValidatedSignal;
   using AfterLsdbModified = ndn::signal::Signal<Lsdb, std::shared_ptr<Lsa>, LsdbUpdate,
-                                                std::list<ndn::Name>, std::list<ndn::Name>>;
+                                                std::list<nlsr::PrefixInfo>, std::list<nlsr::PrefixInfo>>;
   AfterLsdbModified onLsdbModified;
 
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
diff --git a/src/name-prefix-list.cpp b/src/name-prefix-list.cpp
index 0323896..8012306 100644
--- a/src/name-prefix-list.cpp
+++ b/src/name-prefix-list.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2023,  The University of Memphis,
+ * Copyright (c) 2014-2025,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -21,6 +21,7 @@
 
 #include "name-prefix-list.hpp"
 #include "common.hpp"
+#include "tlv-nlsr.hpp"
 
 namespace nlsr {
 
@@ -34,10 +35,19 @@
 }
 
 bool
-NamePrefixList::insert(const ndn::Name& name, const std::string& source)
+NamePrefixList::insert(const ndn::Name& name, const std::string& source, double cost)
 {
-  auto& sources = m_namesSources[name];
-  return sources.insert(source).second;
+  auto& soucePrefixInfo = m_namesSources[name];
+  soucePrefixInfo.costObj = PrefixInfo(name, cost);
+  return soucePrefixInfo.sources.insert(source).second;
+}
+
+bool
+NamePrefixList::insert(const PrefixInfo& nameCost)
+{
+  auto& soucePrefixInfo = m_namesSources[nameCost.getName()];
+  soucePrefixInfo.costObj = nameCost;
+  return soucePrefixInfo.sources.insert("").second;
 }
 
 bool
@@ -48,30 +58,48 @@
     return false;
   }
 
-  bool isRemoved = it->second.erase(source);
-  if (it->second.empty()) {
+  bool isRemoved = it->second.sources.erase(source);
+  if (it->second.sources.empty()) {
     m_namesSources.erase(it);
   }
   return isRemoved;
 }
 
+const PrefixInfo&
+NamePrefixList::getPrefixInfoForName(const ndn::Name& name) const
+{
+  auto it = m_namesSources.find(name);
+  BOOST_ASSERT(it != m_namesSources.end());
+  return it->second.costObj;
+}
+
 std::list<ndn::Name>
 NamePrefixList::getNames() const
 {
   std::list<ndn::Name> names;
   for (const auto& [name, sources] : m_namesSources) {
-    names.push_back(name);
+    names.emplace_back(name);
   }
   return names;
 }
 
+std::list<PrefixInfo>
+NamePrefixList::getPrefixInfo() const
+{
+  std::list<PrefixInfo> nameCosts;
+  for (const auto& [name, soucePrefixInfo] : m_namesSources) {
+    nameCosts.emplace_back(name, soucePrefixInfo.costObj.getCost());
+  }
+  return nameCosts;
+}
+
 #ifdef WITH_TESTS
 
 std::set<std::string>
 NamePrefixList::getSources(const ndn::Name& name) const
 {
   if (auto it = m_namesSources.find(name); it != m_namesSources.end()) {
-    return it->second;
+    return it->second.sources;
   }
   return {};
 }
@@ -84,7 +112,7 @@
   os << "Name prefix list: {\n";
   for (const auto& [name, sources] : list.m_namesSources) {
     os << name << "\nSources:\n";
-    for (const auto& source : sources) {
+    for (const auto& source : sources.sources) {
       os << "  " << source << "\n";
     }
   }
@@ -92,4 +120,70 @@
   return os;
 }
 
+template<ndn::encoding::Tag TAG>
+size_t
+PrefixInfo::wireEncode(ndn::EncodingImpl<TAG>& encoder) const
+{
+  size_t totalLength = 0;
+
+  totalLength += prependDoubleBlock(encoder, nlsr::tlv::Cost, m_prefixCost);
+
+  totalLength += m_prefixName.wireEncode(encoder);
+
+  totalLength += encoder.prependVarNumber(totalLength);
+  totalLength += encoder.prependVarNumber(nlsr::tlv::PrefixInfo);
+
+  return totalLength;
+}
+
+NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(PrefixInfo);
+
+const ndn::Block&
+PrefixInfo::wireEncode() const
+{
+  if (m_wire.hasWire()) {
+    return m_wire;
+  }
+
+  ndn::EncodingEstimator estimator;
+  size_t estimatedSize = wireEncode(estimator);
+
+  ndn::EncodingBuffer buffer(estimatedSize, 0);
+  wireEncode(buffer);
+
+  m_wire = buffer.block();
+
+  return m_wire;
+}
+
+void
+PrefixInfo::wireDecode(const ndn::Block& wire)
+{
+  m_wire = wire;
+
+  if (m_wire.type() != nlsr::tlv::PrefixInfo) {
+    NDN_THROW(Error("PrefixInfo", m_wire.type()));
+  }
+
+  m_wire.parse();
+
+  auto val = m_wire.elements_begin();
+
+  if (val != m_wire.elements_end() && val->type() == ndn::tlv::Name) {
+    m_prefixName.wireDecode(*val);
+    ++val;
+  }
+  else {
+    NDN_THROW(Error("Missing required Name field"));
+  }
+
+  if (val != m_wire.elements_end() && val->type() == nlsr::tlv::Cost) {
+    m_prefixCost = ndn::encoding::readDouble(*val);
+    ++val;
+  }
+  else {
+    NDN_THROW(Error("Missing required Cost field"));
+  }
+}
+
 } // namespace nlsr
diff --git a/src/name-prefix-list.hpp b/src/name-prefix-list.hpp
index 8adaf24..9ea814a 100644
--- a/src/name-prefix-list.hpp
+++ b/src/name-prefix-list.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2023,  The University of Memphis,
+ * Copyright (c) 2014-2025,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -36,6 +36,69 @@
 
 namespace nlsr {
 
+class PrefixInfo : private boost::equality_comparable<PrefixInfo>
+{
+public:
+  class Error : public ndn::tlv::Error
+  {
+  public:
+    using ndn::tlv::Error::Error;
+  };
+
+  PrefixInfo() = default;
+
+  PrefixInfo(const ndn::Block& block)
+  {
+    wireDecode(block);
+  }
+
+  PrefixInfo(const ndn::Name& name, double cost)
+    : m_prefixName(name),
+      m_prefixCost(cost)
+  {
+  }
+
+  const ndn::Name& getName() const
+  {
+    return m_prefixName;
+  }
+
+  double getCost() const
+  {
+    return m_prefixCost;
+  }
+
+  template<ndn::encoding::Tag TAG>
+  size_t
+  wireEncode(ndn::EncodingImpl<TAG>& block) const;
+
+  const ndn::Block&
+  wireEncode() const;
+
+  void
+  wireDecode(const ndn::Block& wire);
+
+private:
+  friend bool
+  operator==(const PrefixInfo& lhs, const PrefixInfo& rhs)
+  {
+    return (lhs.getName() == rhs.getName()) && (lhs.getCost() == rhs.getCost());
+  }
+
+  friend std::ostream&
+  operator<<(std::ostream& os, const PrefixInfo& info)
+  {
+    os << "Prefix Info: (" << info.getName() << ", " << info.getCost() << ")\n";
+    return os;
+  }
+
+private:
+  ndn::Name m_prefixName;
+  double m_prefixCost;
+
+  mutable ndn::Block m_wire;
+};
+
 class NamePrefixList : private boost::equality_comparable<NamePrefixList>
 {
 public:
@@ -49,7 +112,10 @@
       \retval false Name and source combination already exists.
    */
   bool
-  insert(const ndn::Name& name, const std::string& source = "");
+  insert(const ndn::Name& name, const std::string& source = "", double cost = 0);
+
+  bool
+  insert(const PrefixInfo& nameCost);
 
   /*! \brief Deletes name and source combination
       \retval true Name and source combination is deleted.
@@ -64,9 +130,15 @@
     return m_namesSources.size();
   }
 
+  const PrefixInfo&
+  getPrefixInfoForName(const ndn::Name& name) const;
+
   std::list<ndn::Name>
   getNames() const;
 
+  std::list<PrefixInfo>
+  getPrefixInfo() const;
+
 #ifdef WITH_TESTS
   /*! Returns the sources that this name has.
       If the name does not exist, returns an empty container.
@@ -89,16 +161,26 @@
   friend bool
   operator==(const NamePrefixList& lhs, const NamePrefixList& rhs)
   {
-    return lhs.getNames() == rhs.getNames();
+    return lhs.getPrefixInfo() == rhs.getPrefixInfo();
   }
 
+  struct PrefixInfoSource
+  {
+    std::set<std::string> sources;
+    // Because NFD only readvertises each prefix once, this will be the first cost
+    // announced via NFD
+    PrefixInfo costObj;
+  };
+
 private:
-  std::map<ndn::Name, std::set<std::string>> m_namesSources;
+  std::map<ndn::Name, PrefixInfoSource> m_namesSources;
 
   friend std::ostream&
   operator<<(std::ostream& os, const NamePrefixList& list);
 };
 
+NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(PrefixInfo);
+
 } // namespace nlsr
 
 #endif // NLSR_NAME_PREFIX_LIST_HPP
diff --git a/src/route/name-prefix-table-entry.hpp b/src/route/name-prefix-table-entry.hpp
index c298e97..d808018 100644
--- a/src/route/name-prefix-table-entry.hpp
+++ b/src/route/name-prefix-table-entry.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2020,  The University of Memphis,
+ * Copyright (c) 2014-2025,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -24,6 +24,7 @@
 
 #include "routing-table-pool-entry.hpp"
 #include "test-access-control.hpp"
+#include "nexthop.hpp"
 
 #include <list>
 #include <utility>
@@ -80,6 +81,12 @@
     return m_nexthopList;
   }
 
+  NexthopList&
+  getNexthopListForModification()
+  {
+    return m_nexthopList;
+  }
+
   /*! \brief Collect all next-hops that are advertised by this entry's
    * routing entries.
    */
diff --git a/src/route/name-prefix-table.cpp b/src/route/name-prefix-table.cpp
index 3ee9132..ea4fc16 100644
--- a/src/route/name-prefix-table.cpp
+++ b/src/route/name-prefix-table.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2022,  The University of Memphis,
+ * Copyright (c) 2014-2025,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -62,8 +62,8 @@
 
 void
 NamePrefixTable::updateFromLsdb(std::shared_ptr<Lsa> lsa, LsdbUpdate updateType,
-                                const std::list<ndn::Name>& namesToAdd,
-                                const std::list<ndn::Name>& namesToRemove)
+                                const std::list<nlsr::PrefixInfo>& namesToAdd,
+                                const std::list<nlsr::PrefixInfo>& namesToRemove)
 {
   if (m_ownRouterName == lsa->getOriginRouter()) {
     return;
@@ -75,9 +75,10 @@
 
     if (lsa->getType() == Lsa::Type::NAME) {
       auto nlsa = std::static_pointer_cast<NameLsa>(lsa);
-      for (const auto& name : nlsa->getNpl().getNames()) {
-        if (name != m_ownRouterName) {
-          addEntry(name, lsa->getOriginRouter());
+      for (const auto &prefix : nlsa->getNpl().getPrefixInfo()) {
+        if (prefix.getName() != m_ownRouterName) {
+          m_nexthopCost[DestNameKey(lsa->getOriginRouter(), prefix.getName())] = prefix.getCost();
+          addEntry(prefix.getName(), lsa->getOriginRouter());
         }
       }
     }
@@ -87,15 +88,17 @@
       return;
     }
 
-    for (const auto& name : namesToAdd) {
-      if (name != m_ownRouterName) {
-        addEntry(name, lsa->getOriginRouter());
+    for (const auto &prefix : namesToAdd) {
+      if (prefix.getName() != m_ownRouterName) {
+        m_nexthopCost[DestNameKey(lsa->getOriginRouter(), prefix.getName())] = prefix.getCost();
+        addEntry(prefix.getName(), lsa->getOriginRouter());
       }
     }
 
-    for (const auto& name : namesToRemove) {
-      if (name != m_ownRouterName) {
-        removeEntry(name, lsa->getOriginRouter());
+    for (const auto &prefix : namesToRemove) {
+      if (prefix.getName() != m_ownRouterName) {
+        m_nexthopCost.erase(m_nexthopCost.find(DestNameKey(lsa->getOriginRouter(), prefix.getName())));
+        removeEntry(prefix.getName(), lsa->getOriginRouter());
       }
     }
   }
@@ -105,6 +108,7 @@
       auto nlsa = std::static_pointer_cast<NameLsa>(lsa);
       for (const auto& name : nlsa->getNpl().getNames()) {
         if (name != m_ownRouterName) {
+          m_nexthopCost.erase(m_nexthopCost.find(DestNameKey(lsa->getOriginRouter(), name)));
           removeEntry(name, lsa->getOriginRouter());
         }
       }
@@ -112,6 +116,18 @@
   }
 }
 
+NexthopList
+NamePrefixTable::adjustNexthopCosts(const NexthopList& nhlist, const ndn::Name& nameToCheck, const ndn::Name& destRouterName)
+{
+  NexthopList new_nhList;
+  for (const auto& nh : nhlist.getNextHops()) {
+      const NextHop newNextHop = NextHop(nh.getConnectingFaceUri(), nh.getRouteCost() +
+                                              m_nexthopCost[DestNameKey(destRouterName, nameToCheck)]);
+      new_nhList.addNextHop(newNextHop);
+  }
+  return new_nhList;
+}
+
 void
 NamePrefixTable::addEntry(const ndn::Name& name, const ndn::Name& destRouter)
 {
@@ -161,7 +177,7 @@
     // If this entry has next hops, we need to inform the FIB
     if (npte->getNexthopList().size() > 0) {
       NLSR_LOG_TRACE("Updating FIB with next hops for " << npte->getNamePrefix());
-      m_fib.update(name, npte->getNexthopList());
+      m_fib.update(name, adjustNexthopCosts(npte->getNexthopList(), name, destRouter));
     }
     // The routing table may recalculate and add a routing table entry
     // with no next hops to replace an existing routing table entry. In
@@ -183,7 +199,7 @@
 
     if ((*nameItr)->getNexthopList().size() > 0) {
       NLSR_LOG_TRACE("Updating FIB with next hops for " << (**nameItr));
-      m_fib.update(name, (*nameItr)->getNexthopList());
+      m_fib.update(name, adjustNexthopCosts((*nameItr)->getNexthopList(), name, destRouter));
     }
     else {
       NLSR_LOG_TRACE(npte->getNamePrefix() << " has no next hops; removing from FIB");
@@ -251,7 +267,7 @@
       NLSR_LOG_TRACE(**nameItr << " has other routing table entries;"
                      << " updating FIB with next hops");
       (*nameItr)->generateNhlfromRteList();
-      m_fib.update(name, (*nameItr)->getNexthopList());
+      m_fib.update(name, adjustNexthopCosts((*nameItr)->getNexthopList(), name, destRouter));
     }
   }
   else {
diff --git a/src/route/name-prefix-table.hpp b/src/route/name-prefix-table.hpp
index 5ac8345..8fca574 100644
--- a/src/route/name-prefix-table.hpp
+++ b/src/route/name-prefix-table.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2023,  The University of Memphis,
+ * Copyright (c) 2014-2025,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -41,6 +41,7 @@
     std::unordered_map<ndn::Name, std::shared_ptr<RoutingTablePoolEntry>>;
   using NptEntryList = std::list<std::shared_ptr<NamePrefixTableEntry>>;
   using const_iterator = NptEntryList::const_iterator;
+  using DestNameKey = std::tuple<ndn::Name, ndn::Name>;
 
   NamePrefixTable(const ndn::Name& ownRouterName, Fib& fib, RoutingTable& routingTable,
                   AfterRoutingChange& afterRoutingChangeSignal,
@@ -48,6 +49,9 @@
 
   ~NamePrefixTable();
 
+  NexthopList
+  adjustNexthopCosts(const NexthopList& nhlist, const ndn::Name& nameToCheck, const ndn::Name& destRouterName);
+
   /*! \brief Add, update, or remove Names according to the Lsdb update
     \param lsa The LSA class pointer
     \param updateType Update type from Lsdb (INSTALLED, UPDATED, REMOVED)
@@ -56,8 +60,8 @@
    */
   void
   updateFromLsdb(std::shared_ptr<Lsa> lsa, LsdbUpdate updateType,
-                 const std::list<ndn::Name>& namesToAdd,
-                 const std::list<ndn::Name>& namesToRemove);
+                 const std::list<nlsr::PrefixInfo>& namesToAdd,
+                 const std::list<nlsr::PrefixInfo>& namesToRemove);
 
   /*! \brief Adds a destination to the specified name prefix.
     \param name The name prefix
@@ -143,6 +147,7 @@
   RoutingTable& m_routingTable;
   ndn::signal::Connection m_afterRoutingChangeConnection;
   ndn::signal::Connection m_afterLsdbModified;
+  std::map<std::tuple<ndn::Name, ndn::Name>, double> m_nexthopCost;
 };
 
 inline NamePrefixTable::const_iterator
diff --git a/src/tlv-nlsr.hpp b/src/tlv-nlsr.hpp
index 224c452..102e49f 100644
--- a/src/tlv-nlsr.hpp
+++ b/src/tlv-nlsr.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2022,  The University of Memphis,
+ * Copyright (c) 2014-2025,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -46,6 +46,7 @@
   NextHop                     = 143,
   RoutingTable                = 144,
   RoutingTableEntry           = 145,
+  PrefixInfo                  = 146
 };
 
 } // namespace nlsr::tlv
diff --git a/src/update/command-processor.cpp b/src/update/command-processor.cpp
index 67f58cc..f260bd6 100644
--- a/src/update/command-processor.cpp
+++ b/src/update/command-processor.cpp
@@ -50,7 +50,8 @@
                             ? responseParams.getFaceId() : m_defaultResponseFaceId;
   responseParams.setFaceId(responseFaceId);
   // Only build a Name LSA if the added name is new
-  if (m_namePrefixList.insert(castParams.getName())) {
+  double castParamCost = (castParams.hasCost() ? castParams.getCost() : 0);
+  if (m_namePrefixList.insert(castParams.getName(), "", castParamCost)) {
     NLSR_LOG_INFO("Advertising name: " << castParams.getName());
     m_lsdb.buildAndInstallOwnNameLsa();
     if (castParams.hasFlags() && castParams.getFlags() == PREFIX_FLAG) {
diff --git a/tests/lsa/test-name-lsa.cpp b/tests/lsa/test-name-lsa.cpp
index 6f9928e..0634dd7 100644
--- a/tests/lsa/test-name-lsa.cpp
+++ b/tests/lsa/test-name-lsa.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2024,  The University of Memphis,
+ * Copyright (c) 2014-2025,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -20,6 +20,9 @@
  */
 
 #include "lsa/name-lsa.hpp"
+#include "name-prefix-list.hpp"
+
+#include "ndn-cxx/encoding/buffer-stream.hpp"
 
 #include "tests/boost-test.hpp"
 
@@ -28,34 +31,90 @@
 BOOST_AUTO_TEST_SUITE(TestNameLsa)
 
 const uint8_t NAME_LSA1[] = {
-  0x89, 0x37, 0x80, 0x23, 0x07, 0x09, 0x08, 0x07, 0x72, 0x6F, 0x75, 0x74, 0x65, 0x72, 0x31,
-  0x82, 0x01, 0x0C, 0x8B, 0x13, 0x32, 0x30, 0x32, 0x30, 0x2D, 0x30, 0x33, 0x2D, 0x32, 0x36,
-  0x20, 0x30, 0x34, 0x3A, 0x31, 0x33, 0x3A, 0x33, 0x34, 0x07, 0x07, 0x08, 0x05, 0x6E, 0x61,
-  0x6D, 0x65, 0x31, 0x07, 0x07, 0x08, 0x05, 0x6E, 0x61, 0x6D, 0x65, 0x32
+  0x89, 0x4F, //name lsa
+  0x80, 0x23, // lsa
+  0x07, 0x09, 0x08, 0x07, 0x72, 0x6F, 0x75, 0x74, 0x65, 0x72, 0x31, // router name (router1)
+  0x82, 0x01, 0x0C, // sequence number (12)
+  0x8B, 0x13, 0x32, 0x30, 0x32, 0x30, 0x2D, 0x30, 0x33, 0x2D, 0x32, 0x36, 0x20, 0x30, 0x34,
+  0x3A, 0x31, 0x33, 0x3A, 0x33, 0x34, // expiration time
+  0x92, 0x13, // prefix info
+  0x07, 0x07, 0x08, 0x05, 0x6E, 0x61, 0x6D, 0x65, 0x31, // name (name1)
+  0x8C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cost (0)
+  0x92, 0x13, // prefix info
+  0x07, 0x07, 0x08, 0x05, 0x6E, 0x61, 0x6D, 0x65, 0x32, // name (name2)
+  0x8C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cost (0)
 };
 
 const uint8_t NAME_LSA_EXTRA_NAME[] = {
-  0x89, 0x40, 0x80, 0x23, 0x07, 0x09, 0x08, 0x07, 0x72, 0x6F, 0x75, 0x74, 0x65, 0x72, 0x31,
-  0x82, 0x01, 0x0C, 0x8B, 0x13, 0x32, 0x30, 0x32, 0x30, 0x2D, 0x30, 0x33, 0x2D, 0x32, 0x36,
-  0x20, 0x30, 0x34, 0x3A, 0x31, 0x33, 0x3A, 0x33, 0x34, 0x07, 0x07, 0x08, 0x05, 0x6E, 0x61,
-  0x6D, 0x65, 0x31, 0x07, 0x07, 0x08, 0x05, 0x6E, 0x61, 0x6D, 0x65, 0x32, 0x07, 0x07, 0x08,
-  0x05, 0x6E, 0x61, 0x6D, 0x65, 0x33
+  0x89, 0x64, //name lsa
+  0x80, 0x23, // lsa
+  0x07, 0x09, 0x08, 0x07, 0x72, 0x6F, 0x75, 0x74, 0x65, 0x72, 0x31, // router name (router1)
+  0x82, 0x01, 0x0C, // sequence number (12)
+  0x8B, 0x13, 0x32, 0x30, 0x32, 0x30, 0x2D, 0x30, 0x33, 0x2D, 0x32, 0x36, 0x20, 0x30, 0x34,
+  0x3A, 0x31, 0x33, 0x3A, 0x33, 0x34, // expiration time
+  0x92, 0x13, // prefix info
+  0x07, 0x07, 0x08, 0x05, 0x6E, 0x61, 0x6D, 0x65, 0x31, // name (name1)
+  0x8C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cost (0)
+  0x92, 0x13, // prefix info
+  0x07, 0x07, 0x08, 0x05, 0x6E, 0x61, 0x6D, 0x65, 0x32, // name (name2)
+  0x8C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cost (0)
+  0x92, 0x13, // prefix info
+  0x07, 0x07, 0x08, 0x05, 0x6E, 0x61, 0x6D, 0x65, 0x33, // name (name3)
+  0x8C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cost (0)
 };
 
 const uint8_t NAME_LSA_DIFF_SEQ[] = {
-  0x89, 0x40, 0x80, 0x23, 0x07, 0x09, 0x08, 0x07, 0x72, 0x6F, 0x75, 0x74, 0x65, 0x72, 0x31,
-  0x82, 0x01, 0x0E, 0x8B, 0x13, 0x32, 0x30, 0x32, 0x30, 0x2D, 0x30, 0x33, 0x2D, 0x32, 0x36,
-  0x20, 0x30, 0x34, 0x3A, 0x31, 0x33, 0x3A, 0x33, 0x34, 0x07, 0x07, 0x08, 0x05, 0x6E, 0x61,
-  0x6D, 0x65, 0x31, 0x07, 0x07, 0x08, 0x05, 0x6E, 0x61, 0x6D, 0x65, 0x32, 0x07, 0x07, 0x08,
-  0x05, 0x6E, 0x61, 0x6D, 0x65, 0x33
+  0x89, 0x64, //name lsa
+  0x80, 0x23, // lsa
+  0x07, 0x09, 0x08, 0x07, 0x72, 0x6F, 0x75, 0x74, 0x65, 0x72, 0x31, // router name (router1)
+  0x82, 0x01, 0x0E, // sequence number (12)
+  0x8B, 0x13, 0x32, 0x30, 0x32, 0x30, 0x2D, 0x30, 0x33, 0x2D, 0x32, 0x36, 0x20, 0x30, 0x34,
+  0x3A, 0x31, 0x33, 0x3A, 0x33, 0x34, // expiration time
+  0x92, 0x13, // prefix info
+  0x07, 0x07, 0x08, 0x05, 0x6E, 0x61, 0x6D, 0x65, 0x31, // name (name1)
+  0x8C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cost (0)
+  0x92, 0x13, // prefix info
+  0x07, 0x07, 0x08, 0x05, 0x6E, 0x61, 0x6D, 0x65, 0x32, // name (name2)
+  0x8C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cost (0)
+  0x92, 0x13, // prefix info
+  0x07, 0x07, 0x08, 0x05, 0x6E, 0x61, 0x6D, 0x65, 0x33, // name (name3)
+  0x8C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cost (0)
 };
 
 const uint8_t NAME_LSA_DIFF_TS[] = {
-  0x89, 0x40, 0x80, 0x23, 0x07, 0x09, 0x08, 0x07, 0x72, 0x6F, 0x75, 0x74, 0x65, 0x72, 0x31,
-  0x82, 0x01, 0x0E, 0x8B, 0x13, 0x32, 0x30, 0x32, 0x30, 0x2D, 0x30, 0x33, 0x2D, 0x32, 0x36,
-  0x20, 0x30, 0x34, 0x3A, 0x31, 0x33, 0x3A, 0x34, 0x34, 0x07, 0x07, 0x08, 0x05, 0x6E, 0x61,
-  0x6D, 0x65, 0x31, 0x07, 0x07, 0x08, 0x05, 0x6E, 0x61, 0x6D, 0x65, 0x32, 0x07, 0x07, 0x08,
-  0x05, 0x6E, 0x61, 0x6D, 0x65, 0x33
+  0x89, 0x64, //name lsa
+  0x80, 0x23, // lsa
+  0x07, 0x09, 0x08, 0x07, 0x72, 0x6F, 0x75, 0x74, 0x65, 0x72, 0x31, // router name (router1)
+  0x82, 0x01, 0x0E, // sequence number (12)
+  0x8B, 0x13, 0x32, 0x30, 0x32, 0x30, 0x2D, 0x30, 0x33, 0x2D, 0x32, 0x36, 0x20, 0x30, 0x34,
+  0x3A, 0x31, 0x33, 0x3A, 0x34, 0x34, // expiration time (10s higher)
+  0x92, 0x13, // prefix info
+  0x07, 0x07, 0x08, 0x05, 0x6E, 0x61, 0x6D, 0x65, 0x31, // name (name1)
+  0x8C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cost (0)
+  0x92, 0x13, // prefix info
+  0x07, 0x07, 0x08, 0x05, 0x6E, 0x61, 0x6D, 0x65, 0x32, // name (name2)
+  0x8C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cost (0)
+  0x92, 0x13, // prefix info
+  0x07, 0x07, 0x08, 0x05, 0x6E, 0x61, 0x6D, 0x65, 0x33, // name (name3)
+  0x8C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cost (0)
+};
+
+const uint8_t NAME_LSA_DIFF_COST[] = {
+  0x89, 0x64, //name lsa
+  0x80, 0x23, // lsa
+  0x07, 0x09, 0x08, 0x07, 0x72, 0x6F, 0x75, 0x74, 0x65, 0x72, 0x31, // router name (router1)
+  0x82, 0x01, 0x0E, // sequence number (12)
+  0x8B, 0x13, 0x32, 0x30, 0x32, 0x30, 0x2D, 0x30, 0x33, 0x2D, 0x32, 0x36, 0x20, 0x30, 0x34,
+  0x3A, 0x31, 0x33, 0x3A, 0x34, 0x34, // expiration time (10s higher)
+  0x92, 0x13, // prefix info
+  0x07, 0x07, 0x08, 0x05, 0x6E, 0x61, 0x6D, 0x65, 0x31, // name (name1)
+  0x8C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cost (0)
+  0x92, 0x13, // prefix info
+  0x07, 0x07, 0x08, 0x05, 0x6E, 0x61, 0x6D, 0x65, 0x32, // name (name2)
+  0x8C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cost (0)
+  0x92, 0x13, // prefix info
+  0x07, 0x07, 0x08, 0x05, 0x6E, 0x61, 0x6D, 0x65, 0x33, // name (name3)
+  0x8C, 0x08, 0x40, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // cost (10)
 };
 
 BOOST_AUTO_TEST_CASE(Basic)
@@ -76,7 +135,7 @@
   auto wire = nlsa1.wireEncode();
   BOOST_TEST(wire == NAME_LSA1, boost::test_tools::per_element());
 
-  nlsa1.addName("name3");
+  nlsa1.addName(PrefixInfo(ndn::Name("name3"), 0));
   wire = nlsa1.wireEncode();
   BOOST_TEST(wire == NAME_LSA_EXTRA_NAME, boost::test_tools::per_element());
 
@@ -90,6 +149,9 @@
   wire = nlsa1.wireEncode();
   BOOST_TEST(wire == NAME_LSA_DIFF_TS, boost::test_tools::per_element());
 
+  nlsa1.addName(PrefixInfo(ndn::Name("name3"), 10));
+  wire = nlsa1.wireEncode();
+  BOOST_TEST(wire == NAME_LSA_DIFF_COST, boost::test_tools::per_element());
   // Not testing router name as not sure if that will ever change once set
 }
 
@@ -107,9 +169,10 @@
 
 BOOST_AUTO_TEST_CASE(OperatorEquals)
 {
-  ndn::Name name1("/ndn/test/name1");
-  ndn::Name name2("/ndn/test/name2");
-  ndn::Name name3("/ndn/some/other/name1");
+  PrefixInfo name1 = PrefixInfo(ndn::Name("/ndn/test/name1"), 0);
+  PrefixInfo name2 = PrefixInfo(ndn::Name("/ndn/test/name2"), 0);
+  PrefixInfo name3 = PrefixInfo(ndn::Name("/ndn/some/other/name1"), 0);
+  PrefixInfo name4 = PrefixInfo(ndn::Name("/ndn/some/other/name1"), 1);
 
   NameLsa lsa1;
   lsa1.addName(name1);
@@ -123,6 +186,18 @@
 
   lsa2.addName(name3);
   BOOST_CHECK_EQUAL(lsa1, lsa2);
+
+  NameLsa lsa3;
+  lsa3.addName(name1);
+  lsa3.addName(name2);
+  lsa3.addName(name4);
+  BOOST_CHECK_NE(lsa2, lsa3);
+
+  NameLsa lsa4;
+  lsa4.addName(name1);
+  lsa4.addName(name2);
+  lsa4.addName(name4);
+  BOOST_CHECK_EQUAL(lsa3, lsa4);
 }
 
 BOOST_AUTO_TEST_CASE(Update)
@@ -131,8 +206,8 @@
   knownNameLsa.m_originRouter = ndn::Name("/yoursunny/_/%C1.Router/dal");
   knownNameLsa.m_seqNo = 2683;
   knownNameLsa.setExpirationTimePoint(ndn::time::system_clock::now() + 3561_ms);
-  knownNameLsa.addName("/yoursunny/_/dal");
-  knownNameLsa.addName("/ndn");
+  knownNameLsa.addName(PrefixInfo(ndn::Name("/yoursunny/_/dal"), 0));
+  knownNameLsa.addName(PrefixInfo(ndn::Name("/ndn"), 0));
 
   auto rcvdLsa = std::make_shared<NameLsa>();
   rcvdLsa->m_originRouter = ndn::Name("/yoursunny/_/%C1.Router/dal");
@@ -140,10 +215,10 @@
   rcvdLsa->setExpirationTimePoint(ndn::time::system_clock::now() + 3600_ms);
 
   auto nlsa = std::static_pointer_cast<NameLsa>(rcvdLsa);
-  nlsa->addName("/ndn");
-  nlsa->addName("/yoursunny/_/dal");
-  ndn::Name addedName1("/yoursunny/video/ndn-dpdk_acmicn20_20200917");
-  ndn::Name addedName2("/yoursunny/pushups");
+  nlsa->addName(PrefixInfo(ndn::Name("/ndn"), 0));
+  nlsa->addName(PrefixInfo(ndn::Name("/yoursunny/_/dal"), 0));
+  PrefixInfo addedName1 = PrefixInfo(ndn::Name("/yoursunny/video/ndn-dpdk_acmicn20_20200917"), 0);
+  PrefixInfo addedName2 = PrefixInfo(ndn::Name("/yoursunny/pushups"), 0);
   nlsa->addName(addedName1);
   nlsa->addName(addedName2);
 
diff --git a/tests/route/test-name-prefix-table.cpp b/tests/route/test-name-prefix-table.cpp
index 66c1826..5d10dd8 100644
--- a/tests/route/test-name-prefix-table.cpp
+++ b/tests/route/test-name-prefix-table.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2024,  The University of Memphis,
+ * Copyright (c) 2014-2025,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -20,6 +20,7 @@
  */
 
 #include "route/name-prefix-table.hpp"
+#include "name-prefix-list.hpp"
 #include "route/fib.hpp"
 #include "route/routing-table.hpp"
 #include "lsdb.hpp"
@@ -295,10 +296,12 @@
   NamePrefixList npl1;
   ndn::Name n1("name1");
   ndn::Name n2("name2");
+  PrefixInfo p1 = PrefixInfo(n1, 0);
+  PrefixInfo p2 = PrefixInfo(n2, 0);
   ndn::Name router1("/router1/1");
 
-  npl1.insert(n1);
-  npl1.insert(n2);
+  npl1.insert(p1);
+  npl1.insert(p2);
 
   NameLsa nlsa1(router1, 12, testTimePoint, npl1);
   std::shared_ptr<Lsa> lsaPtr = std::make_shared<NameLsa>(nlsa1);
@@ -311,10 +314,11 @@
   BOOST_CHECK(isNameInNpt(n2));
 
   ndn::Name n3("name3");
+  PrefixInfo p3 = PrefixInfo(n3, 0);
   auto nlsa = std::static_pointer_cast<NameLsa>(lsaPtr);
-  nlsa->removeName(n2);
-  nlsa->addName(n3);
-  npt.updateFromLsdb(lsaPtr, LsdbUpdate::UPDATED, {n3}, {n2});
+  nlsa->removeName(p2);
+  nlsa->addName(p3);
+  npt.updateFromLsdb(lsaPtr, LsdbUpdate::UPDATED, {p3}, {p2});
   BOOST_CHECK(isNameInNpt(n1));
   BOOST_CHECK(!isNameInNpt(n2)); // Removed
   BOOST_CHECK(isNameInNpt(n3));
diff --git a/tests/test-lsa-segment-storage.cpp b/tests/test-lsa-segment-storage.cpp
index 337cdc7..347b1a5 100644
--- a/tests/test-lsa-segment-storage.cpp
+++ b/tests/test-lsa-segment-storage.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2024,  The University of Memphis,
+ * Copyright (c) 2014-2025,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -105,18 +105,23 @@
   advanceClocks(ndn::time::milliseconds(10));
 
   makeLsaContent(lsaInterestName);
-  BOOST_CHECK_EQUAL(ims.size(), 3);
+  //Does seem to be generating 6 segments, but how to validate correct contents?
+  BOOST_CHECK_EQUAL(ims.size(), 6);
 
-  // 1st segment
   sendReplies();
+  // 1st segment
   advanceClocks(ndn::time::milliseconds(10));
   // 2nd and 3rd segments
   sendReplies();
   advanceClocks(ndn::time::milliseconds(10));
+  // 4th and 5th segments
+  sendReplies();
+  // 6th segment
+  advanceClocks(ndn::time::milliseconds(10));
 
   // 3 data segments should be in the storage
-  BOOST_CHECK_EQUAL(lsdb.m_lsaStorage.size(), 3);
-  BOOST_CHECK_EQUAL(numValidationSignal, 3);
+  BOOST_CHECK_EQUAL(lsdb.m_lsaStorage.size(), 6);
+  BOOST_CHECK_EQUAL(numValidationSignal, 6);
   numValidationSignal = 0;
 
   // Remove older LSA from storage upon receiving that of higher sequence
diff --git a/tests/test-lsdb.cpp b/tests/test-lsdb.cpp
index 28cf59e..96eb4d2 100644
--- a/tests/test-lsdb.cpp
+++ b/tests/test-lsdb.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2024,  The University of Memphis,
+ * Copyright (c) 2014-2025,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -67,8 +67,8 @@
   void
   checkSignalResult(LsdbUpdate updateType,
                     const std::shared_ptr<Lsa>& lsaPtr,
-                    const std::list<ndn::Name>& namesToAdd,
-                    const std::list<ndn::Name>& namesToRemove)
+                    const std::list<PrefixInfo>& namesToAdd,
+                    const std::list<PrefixInfo>& namesToRemove)
   {
     BOOST_CHECK(updateHappened);
     BOOST_CHECK_EQUAL(lsaPtrCheck->getOriginRouter(), lsaPtr->getOriginRouter());
@@ -101,8 +101,8 @@
   Lsdb lsdb;
 
   LsdbUpdate updateTypeCheck = LsdbUpdate::INSTALLED;
-  std::list<ndn::Name> namesToAddCheck;
-  std::list<ndn::Name> namesToRemoveCheck;
+  std::list<PrefixInfo> namesToAddCheck;
+  std::list<PrefixInfo> namesToRemoveCheck;
   std::shared_ptr<Lsa> lsaPtrCheck = nullptr;
   bool updateHappened = false;
 };
@@ -190,7 +190,7 @@
 
   int nPrefixes = 0;
   while (nameLsa->wireEncode().size() < ndn::MAX_NDN_PACKET_SIZE) {
-    nameLsa->addName(ndn::Name(prefix).appendNumber(++nPrefixes));
+    nameLsa->addName(PrefixInfo(ndn::Name(prefix).appendNumber(++nPrefixes), 0));
     break;
   }
   lsdb.installLsa(nameLsa);
@@ -232,7 +232,7 @@
 
   int nPrefixes = 0;
   while (lsa->wireEncode().size() < ndn::MAX_NDN_PACKET_SIZE) {
-    lsa->addName(ndn::Name(prefix).appendNumber(++nPrefixes));
+    lsa->addName(PrefixInfo(ndn::Name(prefix).appendNumber(++nPrefixes), 0));
   }
   lsdb.installLsa(lsa);
 
@@ -266,7 +266,7 @@
   ndn::Name prefix("/prefix/");
 
   for (int nPrefixes = 0; nPrefixes < 3; ++nPrefixes) {
-    lsa.addName(ndn::Name(prefix).appendNumber(nPrefixes));
+    lsa.addName(PrefixInfo(ndn::Name(prefix).appendNumber(nPrefixes), 0));
   }
 
   ndn::Name interestName("/localhop/ndn/nlsr/LSA/cs/%C1.Router/router1/NAME/");
@@ -439,7 +439,7 @@
   NameLsa nameLsa2(router2, 14, testTimePoint, npl2);
   lsaPtr = std::make_shared<NameLsa>(nameLsa2);
   lsdb.installLsa(lsaPtr);
-  checkSignalResult(LsdbUpdate::UPDATED, lsaPtr, {"name3"}, {"name1"});
+  checkSignalResult(LsdbUpdate::UPDATED, lsaPtr, {PrefixInfo(ndn::Name("/name3"), 0)}, {PrefixInfo(ndn::Name("/name1"), 0)});
 
   lsdb.removeLsa(lsaPtrCheck->getOriginRouter(), Lsa::Type::NAME);
   checkSignalResult(LsdbUpdate::REMOVED, lsaPtr, {}, {});
diff --git a/tests/test-name-prefix-list.cpp b/tests/test-name-prefix-list.cpp
index 7fd06ca..0863492 100644
--- a/tests/test-name-prefix-list.cpp
+++ b/tests/test-name-prefix-list.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2024,  The University of Memphis,
+ * Copyright (c) 2014-2025,  The University of Memphis,
  *                           Regents of the University of California
  *
  * This file is part of NLSR (Named-data Link State Routing).
@@ -108,7 +108,7 @@
 
 /*
   Two NamePrefixLists will be considered equal if they contain the
-  same names. Sources for names are ignored.
+  same names with the same costs. Sources for names are ignored.
  */
 BOOST_AUTO_TEST_CASE(OperatorEquals)
 {
@@ -129,6 +129,15 @@
 
   list2.erase(name3, "C0");
   BOOST_CHECK_NE(list1, list2);
+
+  list2.insert(name3, "C0");
+  list1.insert(PrefixInfo(name1, 10));
+  list1.insert(PrefixInfo(name2, 20));
+  BOOST_CHECK_NE(list1, list2);
+
+  list2.insert(PrefixInfo(name1, 10));
+  list2.insert(PrefixInfo(name2, 20));
+  BOOST_CHECK_EQUAL(list1, list2);
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/test-statistics.cpp b/tests/test-statistics.cpp
index e4c8a23..bf2c0d9 100644
--- a/tests/test-statistics.cpp
+++ b/tests/test-statistics.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2024,  The University of Memphis,
+ * Copyright (c) 2014-2025,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -23,6 +23,7 @@
 #include "hello-protocol.hpp"
 #include "lsdb.hpp"
 #include "nlsr.hpp"
+#include "name-prefix-list.hpp"
 
 #include "tests/io-key-chain-fixture.hpp"
 #include "tests/test-common.hpp"
@@ -249,7 +250,7 @@
 
   seqNo = nameLsa->getSeqNo();
 
-  nameLsa->addName(ndn::Name("/ndn/name"));
+  nameLsa->addName(PrefixInfo(ndn::Name("/ndn/name"), 0));
   lsdb.installLsa(nameLsa);
 
   // Receive Name LSA Interest