Skip to content

Commit

Permalink
mgmt: handle rib/announce command
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jaczhi authored and Pesa committed Jan 10, 2025
1 parent 1db1bb6 commit b065768
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 6 deletions.
44 changes: 43 additions & 1 deletion daemon/mgmt/rib-manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ RibManager::RibManager(rib::Rib& rib, ndn::Face& face, ndn::KeyChain& keyChain,
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)...);
});
Expand Down Expand Up @@ -265,6 +268,44 @@ RibManager::unregisterEntry(const Interest& interest, ControlParameters paramete
beginRemoveRoute(parameters.getName(), route, [] (auto&&...) {});
}

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)
{
Expand Down Expand Up @@ -311,7 +352,8 @@ RibManager::makeAuthorization(const std::string&)
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;
Expand Down
7 changes: 7 additions & 0 deletions daemon/mgmt/rib-manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,13 @@ class RibManager final : public ManagerBase
unregisterEntry(const Interest& interest, ControlParameters parameters,
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.
*/
Expand Down
4 changes: 1 addition & 3 deletions daemon/rib/route.cpp
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion daemon/rib/route.hpp
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -90,6 +90,9 @@ class Route : public ndn::nfd::RouteFlagsTraits<Route>, private boost::equality_
}

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;
Expand Down
14 changes: 14 additions & 0 deletions tests/daemon/mgmt/manager-common-fixture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,20 @@ InterestSignerFixture::makeControlCommandRequest(Name commandName,
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()
{
Expand Down
13 changes: 13 additions & 0 deletions tests/daemon/mgmt/manager-common-fixture.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,19 @@ class InterestSignerFixture : public GlobalIoTimeFixture, public KeyChainFixture
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"};

Expand Down
114 changes: 113 additions & 1 deletion tests/daemon/mgmt/rib-manager.t.cpp
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -117,6 +117,14 @@ getLocalhopValidatorConfigSection()
return makeSection(config);
}

static ConfigSection
getPaValidatorConfigSection()
{
ConfigSection section;
section.put("trust-anchor.type", "any");
return section;
}

class RibManagerFixture : public ManagerCommonFixture
{
public:
Expand Down Expand Up @@ -151,6 +159,8 @@ class RibManagerFixture : public ManagerCommonFixture
m_manager.disableLocalhop();
}

m_manager.applyPaConfig(getPaValidatorConfigSection(), "testPa");

registerWithNfd();

if (shouldClearRib) {
Expand Down Expand Up @@ -442,6 +452,7 @@ BOOST_AUTO_TEST_CASE(NameTooLong)
}
auto params = makeRegisterParameters(prefix, 2899);
auto command = makeControlCommandRequest("/localhost/nfd/rib/register", params);

receiveInterest(command);

BOOST_REQUIRE_EQUAL(m_responses.size(), 1);
Expand All @@ -455,6 +466,107 @@ BOOST_AUTO_TEST_CASE(NameTooLong)

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;
Expand Down

0 comments on commit b065768

Please sign in to comment.