mgmt: handle rib/announce command

This commit adds logic to NFD so it can handle the new Prefix
Announcement protocol, which are commands sent to rib/announce
with Prefix Announcement object in the Application Parameters.

Refs: #4650
Change-Id: I2a306eb2c3eeb638cc789329d998bfa278880ca6
diff --git a/daemon/mgmt/rib-manager.cpp b/daemon/mgmt/rib-manager.cpp
index 6cc614a..ddc53cf 100644
--- a/daemon/mgmt/rib-manager.cpp
+++ b/daemon/mgmt/rib-manager.cpp
@@ -67,6 +67,9 @@
   registerCommandHandler<ndn::nfd::RibUnregisterCommand>([this] (auto&&, auto&&... args) {
     unregisterEntry(std::forward<decltype(args)>(args)...);
   });
+  registerCommandHandler<ndn::nfd::RibAnnounceCommand>([this] (auto&&, auto&&... args) {
+    announceEntry(std::forward<decltype(args)>(args)...);
+  });
   registerStatusDatasetHandler("list", [this] (auto&&, auto&&, auto&&... args) {
     listEntries(std::forward<decltype(args)>(args)...);
   });
@@ -266,6 +269,44 @@
 }
 
 void
+RibManager::announceEntry(const Interest& interest, const ndn::nfd::RibAnnounceParameters& parameters,
+                          const CommandContinuation& done)
+{
+  const auto& announcement = parameters.getPrefixAnnouncement();
+  if (announcement.getAnnouncedName().size() > Fib::getMaxDepth()) {
+    done(ControlResponse(414, "Route prefix cannot exceed " + std::to_string(Fib::getMaxDepth()) +
+                         " components"));
+    return;
+  }
+
+  // Prepare parameters for response
+  ControlParameters responseParams;
+  responseParams.setFaceId(0);
+  setFaceForSelfRegistration(interest, responseParams);
+
+  Route route(announcement, responseParams.getFaceId());
+
+  responseParams
+    .setName(announcement.getAnnouncedName())
+    .setOrigin(route.origin)
+    .setCost(route.cost)
+    .setFlags(route.flags)
+    .setExpirationPeriod(time::duration_cast<time::milliseconds>(route.annExpires - time::steady_clock::now()));
+
+  BOOST_ASSERT(announcement.getData());
+  m_paValidator.validate(*announcement.getData(),
+    [=, name = announcement.getAnnouncedName(), route = std::move(route)] (const Data&) {
+      // Respond since command is valid and authorized
+      done(ControlResponse(200, "Success").setBody(responseParams.wireEncode()));
+      beginAddRoute(name, std::move(route), std::nullopt, [] (RibUpdateResult) {});
+    },
+    [=] (const Data&, ndn::security::ValidationError err) {
+      done(ControlResponse(403, "Validation error: " + err.getInfo()));
+    }
+  );
+}
+
+void
 RibManager::listEntries(ndn::mgmt::StatusDatasetContext& context)
 {
   auto now = time::steady_clock::now();
@@ -311,7 +352,8 @@
                  const ndn::mgmt::AcceptContinuation& accept,
                  const ndn::mgmt::RejectContinuation& reject) {
     BOOST_ASSERT(params != nullptr);
-    BOOST_ASSERT(typeid(*params) == typeid(ndn::nfd::ControlParameters));
+    BOOST_ASSERT(typeid(*params) == typeid(ndn::nfd::ControlParameters) ||
+                 typeid(*params) == typeid(ndn::nfd::RibAnnounceParameters));
     BOOST_ASSERT(prefix == LOCALHOST_TOP_PREFIX || prefix == LOCALHOP_TOP_PREFIX);
 
     auto& validator = prefix == LOCALHOST_TOP_PREFIX ? m_localhostValidator : m_localhopValidator;
diff --git a/daemon/mgmt/rib-manager.hpp b/daemon/mgmt/rib-manager.hpp
index a7edc22..3b348a1 100644
--- a/daemon/mgmt/rib-manager.hpp
+++ b/daemon/mgmt/rib-manager.hpp
@@ -212,6 +212,13 @@
                   const CommandContinuation& done);
 
   /**
+   * \brief Serve `rib/announce` command.
+   */
+  void
+  announceEntry(const Interest& interest, const ndn::nfd::RibAnnounceParameters& parameters,
+                const CommandContinuation& done);
+
+  /**
    * \brief Serve `rib/list` dataset.
    */
   void
diff --git a/daemon/rib/route.cpp b/daemon/rib/route.cpp
index e7c825f..5011290 100644
--- a/daemon/rib/route.cpp
+++ b/daemon/rib/route.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2023,  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,
@@ -29,8 +29,6 @@
 
 namespace nfd::rib {
 
-constexpr uint64_t PA_ROUTE_COST = 2048; // cost of route created by prefix announcement
-
 Route::Route() = default;
 
 static time::steady_clock::time_point
diff --git a/daemon/rib/route.hpp b/daemon/rib/route.hpp
index 2c275df..43f520d 100644
--- a/daemon/rib/route.hpp
+++ b/daemon/rib/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,
@@ -90,6 +90,9 @@
   }
 
 public:
+  /// Cost of route created by prefix announcement.
+  static constexpr uint64_t PA_ROUTE_COST = 2048;
+
   uint64_t faceId = 0;
   ndn::nfd::RouteOrigin origin = ndn::nfd::ROUTE_ORIGIN_APP;
   uint64_t cost = 0;