blob: 83a0af22b21222553533bacfebe1a5349b6c7d52 [file] [log] [blame]
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
Davide Pesaventod6ea0b12023-03-13 21:35:03 -04003 * Copyright (c) 2014-2023, Regents of the University of California,
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +00004 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
10 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24 */
25
Davide Pesavento8a05c7f2019-02-28 02:26:19 -050026#include "mgmt/rib-manager.hpp"
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +000027
Davide Pesaventocf7db2f2019-03-24 23:17:28 -040028#include "tests/test-common.hpp"
Davide Pesavento1d12d2f2019-03-22 12:44:14 -040029#include "tests/key-chain-fixture.hpp"
Davide Pesaventocf7db2f2019-03-24 23:17:28 -040030#include "tests/daemon/global-io-fixture.hpp"
Junxiao Shidf1dc652019-08-30 19:03:19 +000031#include "tests/daemon/rib/fib-updates-common.hpp"
Davide Pesaventoe1bdc082018-10-11 21:20:23 -040032
Davide Pesavento21353752020-11-20 00:43:44 -050033#include <ndn-cxx/security/transform/base64-encode.hpp>
34#include <ndn-cxx/security/transform/buffer-source.hpp>
35#include <ndn-cxx/security/transform/stream-sink.hpp>
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +000036#include <ndn-cxx/util/dummy-client-face.hpp>
37
Teng Liang18c2b292019-10-18 14:31:04 -070038#include <boost/property_tree/info_parser.hpp>
39
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040040namespace nfd::tests {
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +000041
Davide Pesavento8a05c7f2019-02-28 02:26:19 -050042using rib::Route;
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +000043
Teng Liang18c2b292019-10-18 14:31:04 -070044static ConfigSection
45makeSection(const std::string& config)
46{
47 std::istringstream inputStream(config);
48 ConfigSection section;
49 boost::property_tree::read_info(inputStream, section);
50 return section;
51}
52
Davide Pesaventocf7db2f2019-03-24 23:17:28 -040053class RibManagerSlAnnounceFixture : public GlobalIoTimeFixture, public KeyChainFixture
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +000054{
55public:
56 using SlAnnounceResult = RibManager::SlAnnounceResult;
57
58 RibManagerSlAnnounceFixture()
Davide Pesaventoe1bdc082018-10-11 21:20:23 -040059 : m_face(g_io, m_keyChain)
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +000060 , m_nfdController(m_face, m_keyChain)
61 , m_dispatcher(m_face, m_keyChain)
62 , m_fibUpdater(rib, m_nfdController)
63 , m_trustedSigner(m_keyChain.createIdentity("/trusted", ndn::RsaKeyParams()))
64 , m_untrustedSigner(m_keyChain.createIdentity("/untrusted", ndn::RsaKeyParams()))
65 {
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +000066 // Face, Controller, Dispatcher are irrelevant to SlAnnounce functions but required by
67 // RibManager construction, so they are private. RibManager is a pointer to avoid code style
68 // rule 1.4 violation.
Davide Pesavento0a71dd32019-03-17 20:36:18 -040069 manager = make_unique<RibManager>(rib, m_face, m_keyChain, m_nfdController, m_dispatcher);
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +000070
Teng Liang18c2b292019-10-18 14:31:04 -070071 loadDefaultPaConfig();
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +000072 }
73
Davide Pesaventod7083a52023-10-19 17:51:16 -040074 template<typename... T>
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +000075 ndn::PrefixAnnouncement
Davide Pesavento8a05c7f2019-02-28 02:26:19 -050076 makeTrustedAnn(T&&... args)
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +000077 {
Davide Pesavento8a05c7f2019-02-28 02:26:19 -050078 return signPrefixAnn(makePrefixAnn(std::forward<T>(args)...), m_keyChain, m_trustedSigner);
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +000079 }
80
Davide Pesaventod7083a52023-10-19 17:51:16 -040081 template<typename... T>
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +000082 ndn::PrefixAnnouncement
Davide Pesavento8a05c7f2019-02-28 02:26:19 -050083 makeUntrustedAnn(T&&... args)
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +000084 {
Davide Pesavento8a05c7f2019-02-28 02:26:19 -050085 return signPrefixAnn(makePrefixAnn(std::forward<T>(args)...), m_keyChain, m_untrustedSigner);
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +000086 }
87
88 /** \brief Invoke manager->slAnnounce and wait for result.
89 */
90 SlAnnounceResult
91 slAnnounceSync(const ndn::PrefixAnnouncement& pa, uint64_t faceId, time::milliseconds maxLifetime)
92 {
Davide Pesaventob7bfcb92022-05-22 23:55:23 -040093 std::optional<SlAnnounceResult> result;
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +000094 manager->slAnnounce(pa, faceId, maxLifetime,
95 [&] (RibManager::SlAnnounceResult res) {
96 BOOST_CHECK(!result);
97 result = res;
98 });
99
Davide Pesaventoe1bdc082018-10-11 21:20:23 -0400100 g_io.poll();
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000101 BOOST_CHECK(result);
102 return result.value_or(SlAnnounceResult::ERROR);
103 }
104
105 /** \brief Invoke manager->slRenew and wait for result.
106 */
107 SlAnnounceResult
108 slRenewSync(const Name& name, uint64_t faceId, time::milliseconds maxLifetime)
109 {
Davide Pesaventob7bfcb92022-05-22 23:55:23 -0400110 std::optional<SlAnnounceResult> result;
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000111 manager->slRenew(name, faceId, maxLifetime,
112 [&] (RibManager::SlAnnounceResult res) {
113 BOOST_CHECK(!result);
114 result = res;
115 });
116
Davide Pesaventoe1bdc082018-10-11 21:20:23 -0400117 g_io.poll();
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000118 BOOST_CHECK(result);
119 return result.value_or(SlAnnounceResult::ERROR);
120 }
121
122 /** \brief Invoke manager->slFindAnn and wait for result.
123 */
Davide Pesaventob7bfcb92022-05-22 23:55:23 -0400124 std::optional<ndn::PrefixAnnouncement>
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000125 slFindAnnSync(const Name& name)
126 {
Davide Pesaventob7bfcb92022-05-22 23:55:23 -0400127 std::optional<std::optional<ndn::PrefixAnnouncement>> result;
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000128 manager->slFindAnn(name,
Davide Pesaventob7bfcb92022-05-22 23:55:23 -0400129 [&] (std::optional<ndn::PrefixAnnouncement> found) {
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000130 BOOST_CHECK(!result);
131 result = found;
132 });
133
Davide Pesaventoe1bdc082018-10-11 21:20:23 -0400134 g_io.poll();
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000135 BOOST_CHECK(result);
Davide Pesaventob7bfcb92022-05-22 23:55:23 -0400136 return result.value_or(std::nullopt);
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000137 }
138
139 /** \brief Lookup a route with PREFIXANN origin.
140 */
141 Route*
Davide Pesavento21353752020-11-20 00:43:44 -0500142 findAnnRoute(const Name& name, uint64_t faceId) const
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000143 {
144 Route routeQuery;
145 routeQuery.faceId = faceId;
146 routeQuery.origin = ndn::nfd::ROUTE_ORIGIN_PREFIXANN;
147 return rib.find(name, routeQuery);
148 }
149
Davide Pesavento21353752020-11-20 00:43:44 -0500150 /** \brief Retrieve an identity certificate as a base64 string.
151 */
152 std::string
153 getIdentityCertificateBase64(const Name& identity) const
154 {
Davide Pesavento21353752020-11-20 00:43:44 -0500155 namespace tr = ndn::security::transform;
Davide Pesavento21353752020-11-20 00:43:44 -0500156
Davide Pesaventodeb54272022-03-11 18:51:05 -0500157 auto cert = m_keyChain.getPib().getIdentity(identity).getDefaultKey().getDefaultCertificate();
158 std::ostringstream oss;
159 tr::bufferSource(cert.wireEncode()) >> tr::base64Encode(false) >> tr::streamSink(oss);
Davide Pesavento21353752020-11-20 00:43:44 -0500160 return oss.str();
161 }
162
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000163private:
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000164 void
Teng Liang18c2b292019-10-18 14:31:04 -0700165 loadDefaultPaConfig()
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000166 {
Teng Liang18c2b292019-10-18 14:31:04 -0700167 const std::string CONFIG = R"CONFIG(
168 trust-anchor
169 {
170 type any
171 }
172 )CONFIG";
173 manager->applyPaConfig(makeSection(CONFIG), "default");
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000174 }
175
Davide Pesavento21353752020-11-20 00:43:44 -0500176protected:
Davide Pesavento8a05c7f2019-02-28 02:26:19 -0500177 rib::Rib rib;
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000178 unique_ptr<RibManager> manager;
179
180private:
Davide Pesaventoae430302023-05-11 01:42:46 -0400181 ndn::DummyClientFace m_face;
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000182 ndn::nfd::Controller m_nfdController;
Davide Pesavento78ddcab2019-02-28 22:00:03 -0500183 Dispatcher m_dispatcher;
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400184 MockFibUpdater m_fibUpdater;
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000185
186 ndn::security::SigningInfo m_trustedSigner;
187 ndn::security::SigningInfo m_untrustedSigner;
188};
189
Davide Pesavento8a05c7f2019-02-28 02:26:19 -0500190BOOST_AUTO_TEST_SUITE(Mgmt)
191BOOST_AUTO_TEST_SUITE(TestRibManager)
192BOOST_FIXTURE_TEST_SUITE(SlAnnounce, RibManagerSlAnnounceFixture)
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000193
Teng Liang18c2b292019-10-18 14:31:04 -0700194BOOST_AUTO_TEST_CASE(AnnounceWithDefaultConfig)
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000195{
Teng Liang18c2b292019-10-18 14:31:04 -0700196 auto pa = makeTrustedAnn("/fMXN7UeB", 1_h);
197 BOOST_CHECK_EQUAL(slAnnounceSync(pa, 3275, 1_h), SlAnnounceResult::OK);
198 BOOST_CHECK(findAnnRoute("/fMXN7UeB", 3275) != nullptr);
199
200 auto pa2 = makeUntrustedAnn("/1nzAe0Y4", 1_h);
201 BOOST_CHECK_EQUAL(slAnnounceSync(pa2, 2959, 1_h), SlAnnounceResult::OK);
202 BOOST_CHECK(findAnnRoute("/1nzAe0Y4", 2959) != nullptr);
203}
204
205BOOST_AUTO_TEST_CASE(AnnounceWithEmptyConfig)
206{
207 manager->applyPaConfig(makeSection(""), "empty");
208
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000209 auto pa = makeTrustedAnn("/fMXN7UeB", 1_h);
210 BOOST_CHECK_EQUAL(slAnnounceSync(pa, 3275, 1_h), SlAnnounceResult::VALIDATION_FAILURE);
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000211 BOOST_CHECK(findAnnRoute("/fMXN7UeB", 3275) == nullptr);
Teng Liang18c2b292019-10-18 14:31:04 -0700212
213 auto pa2 = makeUntrustedAnn("/1nzAe0Y4", 1_h);
214 BOOST_CHECK_EQUAL(slAnnounceSync(pa2, 2959, 1_h), SlAnnounceResult::VALIDATION_FAILURE);
215 BOOST_CHECK(findAnnRoute("/1nzAe0Y4", 2959) == nullptr);
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000216}
217
218BOOST_AUTO_TEST_CASE(AnnounceValidationError)
219{
Teng Liang18c2b292019-10-18 14:31:04 -0700220 ConfigSection section;
221 section.put("rule.id", "PA");
222 section.put("rule.for", "data");
223 section.put("rule.checker.type", "customized");
224 section.put("rule.checker.sig-type", "rsa-sha256");
225 section.put("rule.checker.key-locator.type", "name");
226 section.put("rule.checker.key-locator.name", "/trusted");
227 section.put("rule.checker.key-locator.relation", "is-prefix-of");
228 section.put("trust-anchor.type", "base64");
229 section.put("trust-anchor.base64-string", getIdentityCertificateBase64("/trusted"));
230 manager->applyPaConfig(section, "trust-schema.section");
231
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000232 auto pa = makeUntrustedAnn("/1nzAe0Y4", 1_h);
233 BOOST_CHECK_EQUAL(slAnnounceSync(pa, 2959, 1_h), SlAnnounceResult::VALIDATION_FAILURE);
234
235 BOOST_CHECK(findAnnRoute("/1nzAe0Y4", 2959) == nullptr);
236}
237
238BOOST_AUTO_TEST_CASE(AnnounceInsert_AnnLifetime)
239{
240 auto pa = makeTrustedAnn("/EHJYmJz9", 1_h);
241 BOOST_CHECK_EQUAL(slAnnounceSync(pa, 1641, 2_h), SlAnnounceResult::OK);
242
243 Route* route = findAnnRoute("/EHJYmJz9", 1641);
244 BOOST_REQUIRE(route != nullptr);
245 BOOST_CHECK_EQUAL(route->annExpires, time::steady_clock::now() + 1_h);
246 BOOST_CHECK_EQUAL(route->expires.value(), time::steady_clock::now() + 1_h);
247}
248
249BOOST_AUTO_TEST_CASE(AnnounceInsert_ArgLifetime)
250{
251 auto pa = makeTrustedAnn("/BU9Fec9E", 2_h);
252 BOOST_CHECK_EQUAL(slAnnounceSync(pa, 1282, 1_h), SlAnnounceResult::OK);
253
254 Route* route = findAnnRoute("/BU9Fec9E", 1282);
255 BOOST_REQUIRE(route != nullptr);
256 BOOST_CHECK_EQUAL(route->annExpires, time::steady_clock::now() + 2_h);
257 BOOST_CHECK_EQUAL(route->expires.value(), time::steady_clock::now() + 1_h);
258}
259
260BOOST_AUTO_TEST_CASE(AnnounceReplace)
261{
262 auto pa = makeTrustedAnn("/HsBFGvL3", 1_h);
263 BOOST_CHECK_EQUAL(slAnnounceSync(pa, 2813, 1_h), SlAnnounceResult::OK);
264
265 pa = makeTrustedAnn("/HsBFGvL3", 2_h);
266 BOOST_CHECK_EQUAL(slAnnounceSync(pa, 2813, 2_h), SlAnnounceResult::OK);
267
268 Route* route = findAnnRoute("/HsBFGvL3", 2813);
269 BOOST_REQUIRE(route != nullptr);
270 BOOST_CHECK_EQUAL(route->annExpires, time::steady_clock::now() + 2_h);
271 BOOST_CHECK_EQUAL(route->expires.value(), time::steady_clock::now() + 2_h);
272}
273
274BOOST_AUTO_TEST_CASE(AnnounceExpired)
275{
Davide Pesaventod6ea0b12023-03-13 21:35:03 -0400276 auto pa = makeTrustedAnn("/awrVv6V7", 1_h, ndn::security::ValidityPeriod::makeRelative(-3_h, -1_h));
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000277 BOOST_CHECK_EQUAL(slAnnounceSync(pa, 9087, 1_h), SlAnnounceResult::EXPIRED);
278
279 BOOST_CHECK(findAnnRoute("/awrVv6V7", 9087) == nullptr);
280}
281
282BOOST_AUTO_TEST_CASE(RenewNotFound)
283{
284 BOOST_CHECK_EQUAL(slRenewSync("IAYigN73", 1070, 1_h), SlAnnounceResult::NOT_FOUND);
285
286 BOOST_CHECK(findAnnRoute("/IAYigN73", 1070) == nullptr);
287}
288
289BOOST_AUTO_TEST_CASE(RenewProlong_ArgLifetime)
290{
291 auto pa = makeTrustedAnn("/P2IYFqtr", 4_h);
292 BOOST_CHECK_EQUAL(slAnnounceSync(pa, 4506, 2_h), SlAnnounceResult::OK);
293 advanceClocks(1_h); // Route has 1_h remaining lifetime
294
Teng Lianga4e6ec32018-10-21 09:25:00 -0700295 BOOST_CHECK_EQUAL(slRenewSync("/P2IYFqtr/2321", 4506, 2_h), SlAnnounceResult::OK);
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000296
297 Route* route = findAnnRoute("/P2IYFqtr", 4506);
298 BOOST_REQUIRE(route != nullptr);
299 BOOST_CHECK_EQUAL(route->annExpires, time::steady_clock::now() + 3_h);
300 BOOST_CHECK_EQUAL(route->expires.value(), time::steady_clock::now() + 2_h); // set by slRenew
301}
302
303BOOST_AUTO_TEST_CASE(RenewProlong_AnnLifetime)
304{
305 auto pa = makeTrustedAnn("/be01Yiba", 4_h);
306 BOOST_CHECK_EQUAL(slAnnounceSync(pa, 1589, 2_h), SlAnnounceResult::OK);
307 advanceClocks(1_h); // Route has 1_h remaining lifetime
308
Teng Lianga4e6ec32018-10-21 09:25:00 -0700309 BOOST_CHECK_EQUAL(slRenewSync("/be01Yiba/4324", 1589, 5_h), SlAnnounceResult::OK);
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000310
311 Route* route = findAnnRoute("/be01Yiba", 1589);
312 BOOST_REQUIRE(route != nullptr);
313 BOOST_CHECK_EQUAL(route->annExpires, time::steady_clock::now() + 3_h);
314 BOOST_CHECK_EQUAL(route->expires.value(), time::steady_clock::now() + 3_h); // capped by annExpires
315}
316
317BOOST_AUTO_TEST_CASE(RenewShorten)
318{
319 auto pa = makeTrustedAnn("/5XCHYCAd", 4_h);
320 BOOST_CHECK_EQUAL(slAnnounceSync(pa, 3851, 4_h), SlAnnounceResult::OK);
321 advanceClocks(1_h); // Route has 3_h remaining lifetime
322
Teng Lianga4e6ec32018-10-21 09:25:00 -0700323 BOOST_CHECK_EQUAL(slRenewSync("/5XCHYCAd/98934", 3851, 1_h), SlAnnounceResult::OK);
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000324
325 Route* route = findAnnRoute("/5XCHYCAd", 3851);
326 BOOST_REQUIRE(route != nullptr);
327 BOOST_CHECK_EQUAL(route->annExpires, time::steady_clock::now() + 3_h);
328 BOOST_CHECK_EQUAL(route->expires.value(), time::steady_clock::now() + 1_h); // set by slRenew
329}
330
331BOOST_AUTO_TEST_CASE(RenewShorten_Zero)
332{
333 auto pa = makeTrustedAnn("/cdQ7KPNw", 4_h);
334 BOOST_CHECK_EQUAL(slAnnounceSync(pa, 8031, 4_h), SlAnnounceResult::OK);
335 advanceClocks(1_h); // Route has 3_h remaining lifetime
336
Teng Lianga4e6ec32018-10-21 09:25:00 -0700337 BOOST_CHECK_EQUAL(slRenewSync("/cdQ7KPNw/8023", 8031, 0_s), SlAnnounceResult::EXPIRED);
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000338
339 BOOST_CHECK(findAnnRoute("/cdQ7KPNw", 8031) == nullptr);
340}
341
342BOOST_AUTO_TEST_CASE(FindExisting)
343{
344 auto pa = makeTrustedAnn("/JHugsjjr", 1_h);
345 BOOST_CHECK_EQUAL(slAnnounceSync(pa, 2363, 1_h), SlAnnounceResult::OK);
346
347 auto found = slFindAnnSync("/JHugsjjr");
348 BOOST_REQUIRE(found);
349 BOOST_CHECK_EQUAL(found->getAnnouncedName(), "/JHugsjjr");
350 BOOST_CHECK(found->getData());
351
352 auto found2 = slFindAnnSync("/JHugsjjr/StvXhKR5");
353 BOOST_CHECK(found == found2);
354}
355
356BOOST_AUTO_TEST_CASE(FindNew)
357{
358 Route route;
359 route.faceId = 1367;
360 route.origin = ndn::nfd::ROUTE_ORIGIN_APP;
361 rib.insert("/dLY1pRhR", route);
362
363 auto pa = slFindAnnSync("/dLY1pRhR/3qNK9Ngn");
364 BOOST_REQUIRE(pa);
365 BOOST_CHECK_EQUAL(pa->getAnnouncedName(), "/dLY1pRhR");
366}
367
368BOOST_AUTO_TEST_CASE(FindNone)
369{
370 auto pa = slFindAnnSync("/2YNeYuV2");
371 BOOST_CHECK(!pa);
372}
373
Davide Pesavento8a05c7f2019-02-28 02:26:19 -0500374BOOST_AUTO_TEST_SUITE_END() // SlAnnounce
375BOOST_AUTO_TEST_SUITE_END() // TestRibManager
376BOOST_AUTO_TEST_SUITE_END() // Mgmt
Junxiao Shi5ba7dfc2018-09-26 14:24:05 +0000377
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400378} // namespace nfd::tests