rib: add route cost to readvertise functionality

This commit adds the cost property (obtained from RIB) to outbound
readvertisements to NLSR.

Change-Id: Idb2e1780dfe1b57f95cfdbb2471b27f832d2671a
diff --git a/daemon/rib/readvertise/client-to-nlsr-readvertise-policy.cpp b/daemon/rib/readvertise/client-to-nlsr-readvertise-policy.cpp
index dcce60a..94c340b 100644
--- a/daemon/rib/readvertise/client-to-nlsr-readvertise-policy.cpp
+++ b/daemon/rib/readvertise/client-to-nlsr-readvertise-policy.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2022,  Regents of the University of California,
+ * Copyright (c) 2014-2025,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -31,7 +31,7 @@
 ClientToNlsrReadvertisePolicy::handleNewRoute(const RibRouteRef& ribRoute) const
 {
   if (ribRoute.route->origin == ndn::nfd::ROUTE_ORIGIN_CLIENT) {
-    return ReadvertiseAction{ribRoute.entry->getName(), ndn::security::SigningInfo()};
+    return ReadvertiseAction{ribRoute.entry->getName(), ribRoute.route->cost, ndn::security::SigningInfo()};
   }
   else {
     return std::nullopt;
diff --git a/daemon/rib/readvertise/host-to-gateway-readvertise-policy.cpp b/daemon/rib/readvertise/host-to-gateway-readvertise-policy.cpp
index ade9f8b..109135e 100644
--- a/daemon/rib/readvertise/host-to-gateway-readvertise-policy.cpp
+++ b/daemon/rib/readvertise/host-to-gateway-readvertise-policy.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2022,  Regents of the University of California,
+ * Copyright (c) 2014-2025,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -75,7 +75,7 @@
   if (!isFound) {
     return std::nullopt;
   }
-  return ReadvertiseAction{prefixToAdvertise, ndn::security::signingByIdentity(signingIdentity)};
+  return ReadvertiseAction{prefixToAdvertise, ribRoute.route->cost, ndn::security::signingByIdentity(signingIdentity)};
 }
 
 time::milliseconds
diff --git a/daemon/rib/readvertise/nfd-rib-readvertise-destination.cpp b/daemon/rib/readvertise/nfd-rib-readvertise-destination.cpp
index 413320e..8504e03 100644
--- a/daemon/rib/readvertise/nfd-rib-readvertise-destination.cpp
+++ b/daemon/rib/readvertise/nfd-rib-readvertise-destination.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2022,  Regents of the University of California,
+ * Copyright (c) 2014-2025,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -64,7 +64,7 @@
   NFD_LOG_DEBUG("advertise " << rr.prefix << " on " << m_commandOptions.getPrefix());
 
   m_controller.start<ndn::nfd::RibRegisterCommand>(
-    getControlParameters().setName(rr.prefix),
+    getControlParameters().setName(rr.prefix).setCost(rr.cost),
     [=] (const ControlParameters&) { successCb(); },
     [=] (const ControlResponse& cr) { failureCb(cr.getText()); },
     getCommandOptions().setSigningInfo(rr.signer));
diff --git a/daemon/rib/readvertise/readvertise-policy.hpp b/daemon/rib/readvertise/readvertise-policy.hpp
index 94d178f..d0d36e5 100644
--- a/daemon/rib/readvertise/readvertise-policy.hpp
+++ b/daemon/rib/readvertise/readvertise-policy.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2022,  Regents of the University of California,
+ * Copyright (c) 2014-2025,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -37,6 +37,7 @@
 struct ReadvertiseAction
 {
   Name prefix; ///< the prefix that should be readvertised
+  uint64_t cost; ///< route cost
   ndn::security::SigningInfo signer; ///< credentials for command signing
 };
 
diff --git a/daemon/rib/readvertise/readvertise.cpp b/daemon/rib/readvertise/readvertise.cpp
index 1df539d..0d07413 100644
--- a/daemon/rib/readvertise/readvertise.cpp
+++ b/daemon/rib/readvertise/readvertise.cpp
@@ -73,7 +73,7 @@
     return;
   }
 
-  auto [rrIt, isNewRr] = m_rrs.emplace(action->prefix);
+  auto [rrIt, isNewRr] = m_rrs.emplace(action->prefix, action->cost);
   if (!isNewRr && rrIt->signer != action->signer) {
     NFD_LOG_WARN("add-route " << ribRoute.entry->getName() << " face=" << ribRoute.route->faceId <<
                  " origin=" << ribRoute.route->origin << " -> readvertising-as " << action->prefix <<
@@ -92,7 +92,7 @@
 
   NFD_LOG_DEBUG("add-route " << ribRoute.entry->getName() << " face=" << ribRoute.route->faceId <<
                 " origin=" << ribRoute.route->origin << " -> readvertising-as " << action->prefix <<
-                " signer=" << action->signer);
+                " cost=" << action->cost << " signer=" << action->signer);
   rrIt->retryDelay = RETRY_DELAY_MIN;
   this->advertise(rrIt);
 }
diff --git a/daemon/rib/readvertise/readvertised-route.hpp b/daemon/rib/readvertise/readvertised-route.hpp
index c4e0ac7..e3c2173 100644
--- a/daemon/rib/readvertise/readvertised-route.hpp
+++ b/daemon/rib/readvertise/readvertised-route.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2024,  Regents of the University of California,
+ * Copyright (c) 2014-2025,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -41,9 +41,9 @@
 class ReadvertisedRoute : noncopyable
 {
 public:
-  explicit
-  ReadvertisedRoute(const Name& prefix)
+  ReadvertisedRoute(const Name& prefix, uint64_t cost)
     : prefix(prefix)
+    , cost(cost)
   {
   }
 
@@ -55,6 +55,7 @@
 
 public:
   Name prefix; ///< readvertised prefix
+  uint64_t cost; ///< cost to reach the prefix
   mutable ndn::security::SigningInfo signer; ///< signer for commands
   mutable size_t nRibRoutes = 0; ///< number of RIB routes that cause the readvertisement
   mutable time::milliseconds retryDelay = 0_ms; ///< retry interval (not used for refresh)
diff --git a/tests/daemon/rib/readvertise/host-to-gateway-readvertise-policy.t.cpp b/tests/daemon/rib/readvertise/host-to-gateway-readvertise-policy.t.cpp
index e9979d2..3c9dd5e 100644
--- a/tests/daemon/rib/readvertise/host-to-gateway-readvertise-policy.t.cpp
+++ b/tests/daemon/rib/readvertise/host-to-gateway-readvertise-policy.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2024,  Regents of the University of California,
+ * Copyright (c) 2014-2025,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -43,6 +43,7 @@
     entry->setName(prefix);
 
     Route route;
+    route.cost = 200;
     auto routeIt = entry->insertRoute(route).first;
     return RibRouteRef{entry, routeIt};
   }
@@ -63,45 +64,46 @@
   BOOST_REQUIRE(m_keyChain.createIdentity("/A/B"));
   BOOST_REQUIRE(m_keyChain.createIdentity("/C/nrd"));
 
-  auto test = [this] (Name routeName, std::optional<ReadvertiseAction> expectedAction) {
-    auto policy = makePolicy();
+  auto policy = makePolicy();
+  auto test = [&policy] (Name routeName, std::optional<ReadvertiseAction> expectedAction) {
     auto action = policy->handleNewRoute(makeNewRoute(routeName));
 
     if (expectedAction) {
       BOOST_REQUIRE(action);
-      BOOST_CHECK_EQUAL(action->prefix, expectedAction->prefix);
-      BOOST_REQUIRE_EQUAL(action->signer, expectedAction->signer);
+      BOOST_TEST(action->prefix == expectedAction->prefix);
+      BOOST_TEST(action->cost == expectedAction->cost);
+      BOOST_TEST(action->signer == expectedAction->signer);
     }
     else {
-      BOOST_REQUIRE(!action);
+      BOOST_TEST(!action);
     }
   };
 
   test("/D/app", std::nullopt);
-  test("/A/B/app", ReadvertiseAction{"/A", ndn::security::signingByIdentity("/A")});
-  test("/C/nrd", ReadvertiseAction{"/C", ndn::security::signingByIdentity("/C/nrd")});
+  test("/A/B/app", ReadvertiseAction{"/A", 200, ndn::security::signingByIdentity("/A")});
+  test("/C/nrd", ReadvertiseAction{"/C", 200, ndn::security::signingByIdentity("/C/nrd")});
 }
 
 BOOST_AUTO_TEST_CASE(DontReadvertise)
 {
   auto policy = makePolicy();
-  BOOST_REQUIRE(!policy->handleNewRoute(makeNewRoute("/localhost/test")));
-  BOOST_REQUIRE(!policy->handleNewRoute(makeNewRoute("/localhop/nfd")));
+  BOOST_TEST(!policy->handleNewRoute(makeNewRoute("/localhost/test")));
+  BOOST_TEST(!policy->handleNewRoute(makeNewRoute("/localhop/nfd")));
 }
 
 BOOST_AUTO_TEST_CASE(LoadRefreshInterval)
 {
   auto policy = makePolicy();
-  BOOST_CHECK_EQUAL(policy->getRefreshInterval(), 25_s); // default setting is 25
+  BOOST_TEST(policy->getRefreshInterval() == 25_s); // default setting is 25s
 
   ConfigSection section;
   section.put("refresh_interval_wrong", 10);
   policy = makePolicy(section);
-  BOOST_CHECK_EQUAL(policy->getRefreshInterval(), 25_s); // wrong formate
+  BOOST_TEST(policy->getRefreshInterval() == 25_s); // wrong syntax
 
   section.put("refresh_interval", 10);
   policy = makePolicy(section);
-  BOOST_CHECK_EQUAL(policy->getRefreshInterval(), 10_s);
+  BOOST_TEST(policy->getRefreshInterval() == 10_s);
 }
 
 BOOST_AUTO_TEST_SUITE_END() // TestHostToGatewayReadvertisePolicy
diff --git a/tests/daemon/rib/readvertise/nfd-rib-readvertise-destination.t.cpp b/tests/daemon/rib/readvertise/nfd-rib-readvertise-destination.t.cpp
index e6d9988..a9dd037 100644
--- a/tests/daemon/rib/readvertise/nfd-rib-readvertise-destination.t.cpp
+++ b/tests/daemon/rib/readvertise/nfd-rib-readvertise-destination.t.cpp
@@ -103,7 +103,7 @@
 BOOST_AUTO_TEST_CASE_TEMPLATE(Advertise, Scenario, AdvertiseScenarios)
 {
   Name prefix("/ndn/memphis/test");
-  ReadvertisedRoute rr(prefix);
+  ReadvertisedRoute rr(prefix, 100);
 
   dest.advertise(rr, successCallback, failureCallback);
   advanceClocks(100_ms);
@@ -111,14 +111,13 @@
   // Retrieve the sent Interest to build the response
   BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
   const Interest& sentInterest = face.sentInterests[0];
-  BOOST_CHECK(RIB_REGISTER_COMMAND_PREFIX.isPrefixOf(sentInterest.getName()));
+  BOOST_TEST(RIB_REGISTER_COMMAND_PREFIX.isPrefixOf(sentInterest.getName()));
 
-  // Parse the sent command Interest to check correctness.
-  ControlParameters sentCp;
-  BOOST_CHECK_NO_THROW(sentCp.wireDecode(sentInterest.getName().get(RIB_REGISTER_COMMAND_PREFIX.size())
-                                         .blockFromValue()));
-  BOOST_CHECK_EQUAL(sentCp.getOrigin(), ndn::nfd::ROUTE_ORIGIN_CLIENT);
-  BOOST_CHECK_EQUAL(sentCp.getName(), prefix);
+  // Parse the sent command Interest parameters to check correctness
+  ControlParameters sentCp(sentInterest.getName().get(RIB_REGISTER_COMMAND_PREFIX.size()).blockFromValue());
+  BOOST_TEST(sentCp.getName() == prefix);
+  BOOST_TEST(sentCp.getOrigin() == ndn::nfd::ROUTE_ORIGIN_CLIENT);
+  BOOST_TEST(sentCp.getCost() == 100);
 
   ndn::nfd::ControlResponse responsePayload = Scenario::makeResponse(sentCp);
   auto responseData = makeData(sentInterest.getName());
@@ -169,7 +168,7 @@
 BOOST_AUTO_TEST_CASE_TEMPLATE(Withdraw, Scenario, WithdrawScenarios)
 {
   Name prefix("/ndn/memphis/test");
-  ReadvertisedRoute rr(prefix);
+  ReadvertisedRoute rr(prefix, 100);
 
   dest.withdraw(rr, successCallback, failureCallback);
   this->advanceClocks(10_ms);
@@ -177,13 +176,12 @@
   // Retrieve the sent Interest to build the response
   BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
   const Interest& sentInterest = face.sentInterests[0];
-  BOOST_CHECK(RIB_UNREGISTER_COMMAND_PREFIX.isPrefixOf(sentInterest.getName()));
+  BOOST_TEST(RIB_UNREGISTER_COMMAND_PREFIX.isPrefixOf(sentInterest.getName()));
 
-  ControlParameters sentCp;
-  BOOST_CHECK_NO_THROW(sentCp.wireDecode(sentInterest.getName().get(RIB_UNREGISTER_COMMAND_PREFIX.size())
-                                         .blockFromValue()));
-  BOOST_CHECK_EQUAL(sentCp.getOrigin(), ndn::nfd::ROUTE_ORIGIN_CLIENT);
-  BOOST_CHECK_EQUAL(sentCp.getName(), prefix);
+  // Parse the sent command Interest parameters to check correctness
+  ControlParameters sentCp(sentInterest.getName().get(RIB_UNREGISTER_COMMAND_PREFIX.size()).blockFromValue());
+  BOOST_TEST(sentCp.getName() == prefix);
+  BOOST_TEST(sentCp.getOrigin() == ndn::nfd::ROUTE_ORIGIN_CLIENT);
 
   ndn::nfd::ControlResponse responsePayload = Scenario::makeResponse(sentCp);
   auto responseData = makeData(sentInterest.getName());
diff --git a/tests/daemon/rib/readvertise/readvertise.t.cpp b/tests/daemon/rib/readvertise/readvertise.t.cpp
index 7f83dfc..84407d8 100644
--- a/tests/daemon/rib/readvertise/readvertise.t.cpp
+++ b/tests/daemon/rib/readvertise/readvertise.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2024,  Regents of the University of California,
+ * Copyright (c) 2014-2025,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -166,7 +166,7 @@
 
 BOOST_AUTO_TEST_CASE(AddRemoveRoute)
 {
-  policy->decision = ReadvertiseAction{"/A", ndn::security::SigningInfo()};
+  policy->decision = ReadvertiseAction{"/A", 200, ndn::security::SigningInfo()};
 
   // advertising /A
   this->insertRoute("/A/1", 1, ndn::nfd::ROUTE_ORIGIN_CLIENT);
@@ -209,9 +209,9 @@
 {
   this->setDestinationAvailability(false);
 
-  policy->decision = ReadvertiseAction{"/A", ndn::security::SigningInfo()};
+  policy->decision = ReadvertiseAction{"/A", 200, ndn::security::SigningInfo()};
   this->insertRoute("/A/1", 1, ndn::nfd::ROUTE_ORIGIN_CLIENT);
-  policy->decision = ReadvertiseAction{"/B", ndn::security::SigningInfo()};
+  policy->decision = ReadvertiseAction{"/B", 200, ndn::security::SigningInfo()};
   this->insertRoute("/B/1", 1, ndn::nfd::ROUTE_ORIGIN_CLIENT);
   BOOST_CHECK_EQUAL(destination->advertiseHistory.size(), 0);
 
@@ -238,7 +238,7 @@
 {
   destination->shouldSucceed = false;
 
-  policy->decision = ReadvertiseAction{"/A", ndn::security::SigningInfo()};
+  policy->decision = ReadvertiseAction{"/A", 200, ndn::security::SigningInfo()};
   this->insertRoute("/A/1", 1, ndn::nfd::ROUTE_ORIGIN_CLIENT);
 
   this->advanceClocks(10_s, 1_h);
@@ -272,7 +272,7 @@
 BOOST_AUTO_TEST_CASE(ChangeDuringRetry)
 {
   destination->shouldSucceed = false;
-  policy->decision = ReadvertiseAction{"/A", ndn::security::SigningInfo()};
+  policy->decision = ReadvertiseAction{"/A", 200, ndn::security::SigningInfo()};
   this->insertRoute("/A/1", 1, ndn::nfd::ROUTE_ORIGIN_CLIENT);
   this->advanceClocks(10_s, 300_s);
   BOOST_CHECK_GT(destination->advertiseHistory.size(), 0);