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/tests/daemon/mgmt/manager-common-fixture.cpp b/tests/daemon/mgmt/manager-common-fixture.cpp
index 3b98dd2..e918cdb 100644
--- a/tests/daemon/mgmt/manager-common-fixture.cpp
+++ b/tests/daemon/mgmt/manager-common-fixture.cpp
@@ -52,6 +52,20 @@
NDN_CXX_UNREACHABLE;
}
+Interest
+InterestSignerFixture::makeControlCommandRequest(Name commandName,
+ const ndn::PrefixAnnouncement& prefixAnnouncement,
+ const Name& identity)
+{
+ const Block& paBlock = prefixAnnouncement.getData().value().wireEncode();
+
+ Interest interest(commandName);
+ interest.setApplicationParameters(paBlock);
+ m_signer.makeSignedInterest(interest, ndn::security::signingByIdentity(identity));
+
+ return interest;
+}
+
void
ManagerCommonFixture::setTopPrefix()
{
diff --git a/tests/daemon/mgmt/manager-common-fixture.hpp b/tests/daemon/mgmt/manager-common-fixture.hpp
index c8f5498..22d9120 100644
--- a/tests/daemon/mgmt/manager-common-fixture.hpp
+++ b/tests/daemon/mgmt/manager-common-fixture.hpp
@@ -59,6 +59,19 @@
ndn::security::SignedInterestFormat format = ndn::security::SignedInterestFormat::V03,
const Name& identity = DEFAULT_COMMAND_SIGNER_IDENTITY);
+ /**
+ * \brief Create a ControlCommand request for a Prefix Announcement.
+ * \param commandName Command name including prefix, such as `/localhost/nfd/rib/announce`
+ * \param prefixAnnouncement Prefix Announcement object
+ * \param identity Signing identity
+ *
+ * Per specification, Prefix Announcements use Signed Interest v0.3 only.
+ */
+ Interest
+ makeControlCommandRequest(Name commandName,
+ const ndn::PrefixAnnouncement& prefixAnnouncement,
+ const Name& identity = DEFAULT_COMMAND_SIGNER_IDENTITY);
+
protected:
static inline const Name DEFAULT_COMMAND_SIGNER_IDENTITY{"/InterestSignerFixture-identity"};
diff --git a/tests/daemon/mgmt/rib-manager.t.cpp b/tests/daemon/mgmt/rib-manager.t.cpp
index 43c69df..679f40c 100644
--- a/tests/daemon/mgmt/rib-manager.t.cpp
+++ b/tests/daemon/mgmt/rib-manager.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,
@@ -117,6 +117,14 @@
return makeSection(config);
}
+static ConfigSection
+getPaValidatorConfigSection()
+{
+ ConfigSection section;
+ section.put("trust-anchor.type", "any");
+ return section;
+}
+
class RibManagerFixture : public ManagerCommonFixture
{
public:
@@ -151,6 +159,8 @@
m_manager.disableLocalhop();
}
+ m_manager.applyPaConfig(getPaValidatorConfigSection(), "testPa");
+
registerWithNfd();
if (shouldClearRib) {
@@ -442,6 +452,7 @@
}
auto params = makeRegisterParameters(prefix, 2899);
auto command = makeControlCommandRequest("/localhost/nfd/rib/register", params);
+
receiveInterest(command);
BOOST_REQUIRE_EQUAL(m_responses.size(), 1);
@@ -455,6 +466,107 @@
BOOST_AUTO_TEST_SUITE_END() // RegisterUnregister
+BOOST_FIXTURE_TEST_SUITE(PrefixAnnounce, LocalhostAuthorizedRibManagerFixture)
+
+BOOST_AUTO_TEST_CASE(Basic)
+{
+ const uint64_t announceFaceId = 1234;
+
+ ndn::PrefixAnnouncement pa = signPrefixAnn(makePrefixAnn("/test-prefix-announce", 10_s), m_keyChain);
+ auto commandAnnounce = makeControlCommandRequest("/localhost/nfd/rib/announce", pa);
+ commandAnnounce.setTag(make_shared<lp::IncomingFaceIdTag>(announceFaceId));
+
+ auto paramsUnregister = makeUnregisterParameters("/test-prefix-announce");
+ paramsUnregister.setOrigin(ndn::nfd::ROUTE_ORIGIN_PREFIXANN);
+ BOOST_CHECK_EQUAL(paramsUnregister.getFaceId(), 0);
+ auto commandUnregister = makeControlCommandRequest("/localhost/nfd/rib/unregister", paramsUnregister);
+ commandUnregister.setTag(make_shared<lp::IncomingFaceIdTag>(announceFaceId)); // same incoming face
+
+ receiveInterest(commandAnnounce);
+ receiveInterest(commandUnregister);
+
+ ControlParameters paramsAnnounceResponse;
+ paramsAnnounceResponse.setName("/test-prefix-announce")
+ .setFaceId(announceFaceId)
+ .setOrigin(ndn::nfd::ROUTE_ORIGIN_PREFIXANN)
+ .setCost(rib::Route::PA_ROUTE_COST)
+ .setFlags(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT)
+ .setExpirationPeriod(10_s);
+ paramsUnregister.setFaceId(announceFaceId);
+
+ BOOST_REQUIRE_EQUAL(m_responses.size(), 2);
+ BOOST_CHECK_EQUAL(checkResponse(0, commandAnnounce.getName(), makeResponse(200, "Success", paramsAnnounceResponse)),
+ CheckResponseResult::OK);
+ BOOST_CHECK_EQUAL(checkResponse(1, commandUnregister.getName(), makeResponse(200, "Success", paramsUnregister)),
+ CheckResponseResult::OK);
+
+ BOOST_REQUIRE_EQUAL(m_fibUpdater.updates.size(), 2);
+ BOOST_CHECK_EQUAL(m_fibUpdater.updates.front(),
+ rib::FibUpdate::createAddUpdate("/test-prefix-announce", announceFaceId, rib::Route::PA_ROUTE_COST));
+ BOOST_CHECK_EQUAL(m_fibUpdater.updates.back(),
+ rib::FibUpdate::createRemoveUpdate("/test-prefix-announce", announceFaceId));
+}
+
+BOOST_AUTO_TEST_CASE(UnregisterFromDifferentFace)
+{
+ const uint64_t announceFaceId = 1234;
+
+ ndn::PrefixAnnouncement pa = signPrefixAnn(makePrefixAnn("/test-prefix-announce", 10_s), m_keyChain);
+ auto commandAnnounce = makeControlCommandRequest("/localhost/nfd/rib/announce", pa);
+ commandAnnounce.setTag(make_shared<lp::IncomingFaceIdTag>(announceFaceId));
+
+ auto paramsUnregister = makeUnregisterParameters("/test-prefix-announce", announceFaceId);
+ paramsUnregister.setOrigin(ndn::nfd::ROUTE_ORIGIN_PREFIXANN);
+ auto commandUnregister = makeControlCommandRequest("/localhost/nfd/rib/unregister", paramsUnregister);
+ commandUnregister.setTag(make_shared<lp::IncomingFaceIdTag>(999)); // unregister from different face
+
+ receiveInterest(commandAnnounce);
+ receiveInterest(commandUnregister);
+
+ ControlParameters paramsAnnounceResponse;
+ paramsAnnounceResponse.setName("/test-prefix-announce")
+ .setFaceId(announceFaceId)
+ .setOrigin(ndn::nfd::ROUTE_ORIGIN_PREFIXANN)
+ .setCost(rib::Route::PA_ROUTE_COST)
+ .setFlags(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT)
+ .setExpirationPeriod(10_s);
+
+ BOOST_REQUIRE_EQUAL(m_responses.size(), 2);
+ BOOST_CHECK_EQUAL(checkResponse(0, commandAnnounce.getName(), makeResponse(200, "Success", paramsAnnounceResponse)),
+ CheckResponseResult::OK);
+ BOOST_CHECK_EQUAL(checkResponse(1, commandUnregister.getName(), makeResponse(200, "Success", paramsUnregister)),
+ CheckResponseResult::OK);
+
+ BOOST_REQUIRE_EQUAL(m_fibUpdater.updates.size(), 2);
+ BOOST_CHECK_EQUAL(m_fibUpdater.updates.front(),
+ rib::FibUpdate::createAddUpdate("/test-prefix-announce", announceFaceId, rib::Route::PA_ROUTE_COST));
+ BOOST_CHECK_EQUAL(m_fibUpdater.updates.back(),
+ rib::FibUpdate::createRemoveUpdate("/test-prefix-announce", announceFaceId));
+}
+
+BOOST_AUTO_TEST_CASE(NameTooLong)
+{
+ Name prefix;
+ while (prefix.size() <= Fib::getMaxDepth()) {
+ prefix.append("A");
+ }
+ ndn::PrefixAnnouncement pa = signPrefixAnn(makePrefixAnn(prefix, 10_s), m_keyChain);
+ auto command = makeControlCommandRequest("/localhost/nfd/rib/announce", pa);
+ command.setTag(make_shared<lp::IncomingFaceIdTag>(333));
+
+ receiveInterest(command);
+
+ BOOST_REQUIRE_EQUAL(m_responses.size(), 1);
+ BOOST_CHECK_EQUAL(checkResponse(0, command.getName(),
+ ControlResponse(414, "Route prefix cannot exceed " +
+ std::to_string(Fib::getMaxDepth()) + " components")),
+ CheckResponseResult::OK);
+
+ BOOST_CHECK_EQUAL(m_fibUpdater.updates.size(), 0);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // PrefixAnnounce
+
BOOST_FIXTURE_TEST_CASE(RibDataset, UnauthorizedRibManagerFixture)
{
uint64_t faceId = 0;