blob: 7232742f364eb435e17bc3fad8c151f46f8a30a1 [file] [log] [blame]
Vince Lehman942eb7b2014-10-02 10:09:27 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Ashlesh Gawande7a231c02020-06-12 20:06:44 -07002/*
awlanefc0b45a2025-05-07 15:51:02 -05003 * Copyright (c) 2014-2025, The University of Memphis,
Nick Gordonf8b5bcd2016-08-11 15:06:50 -05004 * Regents of the University of California
Vince Lehman942eb7b2014-10-02 10:09:27 -05005 *
6 * This file is part of NLSR (Named-data Link State Routing).
7 * See AUTHORS.md for complete list of NLSR authors and contributors.
8 *
9 * NLSR is free software: you can redistribute it and/or modify it under the terms
10 * of the GNU General Public License as published by the Free Software Foundation,
11 * either version 3 of the License, or (at your option) any later version.
12 *
13 * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
14 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * NLSR, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
Ashlesh Gawande7a231c02020-06-12 20:06:44 -070019 */
Vince Lehman942eb7b2014-10-02 10:09:27 -050020
Nick Gordon5867b522017-09-06 17:41:37 -050021#include "route/fib.hpp"
Vince Lehman942eb7b2014-10-02 10:09:27 -050022#include "adjacency-list.hpp"
23#include "conf-parameter.hpp"
24
Davide Pesavento8de8a8b2022-05-12 01:26:43 -040025#include "tests/boost-test.hpp"
26#include "tests/io-key-chain-fixture.hpp"
Davide Pesaventod1f1df82022-03-12 16:40:37 -050027
Davide Pesavento8de8a8b2022-05-12 01:26:43 -040028#include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
Muktadir R Chowdhuryc69da0a2015-12-18 13:24:38 -060029#include <ndn-cxx/util/dummy-client-face.hpp>
30
Davide Pesavento288141a2024-02-13 17:30:35 -050031namespace nlsr::tests {
Vince Lehman942eb7b2014-10-02 10:09:27 -050032
Junxiao Shi6593a432023-08-21 10:50:28 +000033static const ndn::Name router1Name = "/ndn/router1";
34static const ndn::Name router2Name = "/ndn/router2";
35static const ndn::Name router3Name = "/ndn/router3";
36static const ndn::FaceUri router1FaceUri("udp4://10.0.0.1:6363");
37static const ndn::FaceUri router2FaceUri("udp4://10.0.0.2:6363");
38static const ndn::FaceUri router3FaceUri("udp4://10.0.0.3:6363");
39constexpr uint32_t router1FaceId = 1;
40constexpr uint32_t router2FaceId = 2;
41constexpr uint32_t router3FaceId = 3;
42
Davide Pesavento8de8a8b2022-05-12 01:26:43 -040043class FibFixture : public IoKeyChainFixture
Vince Lehman942eb7b2014-10-02 10:09:27 -050044{
45public:
46 FibFixture()
Davide Pesavento8de8a8b2022-05-12 01:26:43 -040047 : adjacencies(conf.getAdjacencyList())
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -070048 , fib(face, m_scheduler, adjacencies, conf, m_keyChain)
49 , interests(face.sentInterests)
Vince Lehman942eb7b2014-10-02 10:09:27 -050050 {
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -070051 advanceClocks(1_s);
52
Junxiao Shi6593a432023-08-21 10:50:28 +000053 Adjacent neighbor1(router1Name, router1FaceUri, 0, Adjacent::STATUS_ACTIVE, 0, router1FaceId);
Vince Lehman942eb7b2014-10-02 10:09:27 -050054 adjacencies.insert(neighbor1);
55
Junxiao Shi6593a432023-08-21 10:50:28 +000056 Adjacent neighbor2(router2Name, router2FaceUri, 0, Adjacent::STATUS_ACTIVE, 0, router2FaceId);
Vince Lehman942eb7b2014-10-02 10:09:27 -050057 adjacencies.insert(neighbor2);
58
Junxiao Shi6593a432023-08-21 10:50:28 +000059 Adjacent neighbor3(router3Name, router3FaceUri, 0, Adjacent::STATUS_ACTIVE, 0, router3FaceId);
Vince Lehman942eb7b2014-10-02 10:09:27 -050060 adjacencies.insert(neighbor3);
61
62 conf.setMaxFacesPerPrefix(2);
63
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -070064 fib.setEntryRefreshTime(1);
65 }
66
Davide Pesavento8de8a8b2022-05-12 01:26:43 -040067 static void
Davide Pesavento69904fc2022-10-14 09:45:34 -040068 extractRibCommandParameters(const ndn::Interest& interest,
69 ndn::Name::Component& verb,
70 ndn::nfd::ControlParameters& params)
Davide Pesavento8de8a8b2022-05-12 01:26:43 -040071 {
Davide Pesavento8de8a8b2022-05-12 01:26:43 -040072 const auto& name = interest.getName();
Davide Pesavento69904fc2022-10-14 09:45:34 -040073 verb = name.at(RIB_COMMAND_PREFIX.size());
74 params.wireDecode(name.at(RIB_COMMAND_PREFIX.size() + 1).blockFromValue());
Davide Pesavento8de8a8b2022-05-12 01:26:43 -040075 }
76
77private:
Davide Pesavento69904fc2022-10-14 09:45:34 -040078 static inline const ndn::Name RIB_COMMAND_PREFIX{"/localhost/nfd/rib"};
79
Davide Pesavento8de8a8b2022-05-12 01:26:43 -040080 ndn::Scheduler m_scheduler{m_io};
81
82public:
Junxiao Shi43f37a02023-08-09 00:09:00 +000083 ndn::DummyClientFace face{m_io, m_keyChain, [] {
84 ndn::DummyClientFace::Options opts;
Junxiao Shi771a0de2023-08-09 00:03:21 +000085 opts.enableRegistrationReply = true;
86 opts.registrationReplyFaceId = 128;
87 return opts;
88 } ()};
Davide Pesavento8de8a8b2022-05-12 01:26:43 -040089 ConfParameter conf{face, m_keyChain};
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -070090 AdjacencyList& adjacencies;
91 Fib fib;
Vince Lehman942eb7b2014-10-02 10:09:27 -050092 std::vector<ndn::Interest>& interests;
Vince Lehman942eb7b2014-10-02 10:09:27 -050093};
94
Vince Lehman942eb7b2014-10-02 10:09:27 -050095BOOST_FIXTURE_TEST_SUITE(TestFib, FibFixture)
96
97BOOST_AUTO_TEST_CASE(NextHopsAdd)
98{
99 NextHop hop1(router1FaceUri, 10);
100 NextHop hop2(router2FaceUri, 20);
101
102 NexthopList hops;
103 hops.addNextHop(hop1);
104 hops.addNextHop(hop2);
105
awlanefc0b45a2025-05-07 15:51:02 -0500106 fib.update("/ndn/name", hops, ndn::nfd::ROUTE_FLAG_CAPTURE);
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700107 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500108
109 // Should register faces 1 and 2 for /ndn/name
110 BOOST_REQUIRE_EQUAL(interests.size(), 2);
111
112 ndn::nfd::ControlParameters extractedParameters;
113 ndn::Name::Component verb;
Davide Pesavento288141a2024-02-13 17:30:35 -0500114 auto it = interests.begin();
Vince Lehman942eb7b2014-10-02 10:09:27 -0500115
116 extractRibCommandParameters(*it, verb, extractedParameters);
117
118 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
119 extractedParameters.getFaceId() == router1FaceId &&
120 verb == ndn::Name::Component("register"));
121
122 ++it;
123 extractRibCommandParameters(*it, verb, extractedParameters);
124
125 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
126 extractedParameters.getFaceId() == router2FaceId &&
127 verb == ndn::Name::Component("register"));
128}
129
Vince Lehman942eb7b2014-10-02 10:09:27 -0500130BOOST_AUTO_TEST_CASE(NextHopsNoChange)
131{
132 NextHop hop1(router1FaceUri, 10);
133 NextHop hop2(router2FaceUri, 20);
134
135 NexthopList oldHops;
136 oldHops.addNextHop(hop1);
137 oldHops.addNextHop(hop2);
138
awlanefc0b45a2025-05-07 15:51:02 -0500139 fib.update("/ndn/name", oldHops, ndn::nfd::ROUTE_FLAG_CAPTURE);
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700140 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500141
142 BOOST_REQUIRE_EQUAL(interests.size(), 2);
143 interests.clear();
144
awlanefc0b45a2025-05-07 15:51:02 -0500145 fib.update("/ndn/name", oldHops, ndn::nfd::ROUTE_FLAG_CAPTURE);
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700146 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500147
148 // Should register face 1 and 2 for /ndn/name
149 BOOST_REQUIRE_EQUAL(interests.size(), 2);
150
151 ndn::nfd::ControlParameters extractedParameters;
152 ndn::Name::Component verb;
Davide Pesavento288141a2024-02-13 17:30:35 -0500153 auto it = interests.begin();
Vince Lehman942eb7b2014-10-02 10:09:27 -0500154
155 extractRibCommandParameters(*it, verb, extractedParameters);
156
157 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
158 extractedParameters.getFaceId() == router1FaceId &&
159 verb == ndn::Name::Component("register"));
160
161 ++it;
162 extractRibCommandParameters(*it, verb, extractedParameters);
163
164 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
165 extractedParameters.getFaceId() == router2FaceId &&
166 verb == ndn::Name::Component("register"));
167}
168
169BOOST_AUTO_TEST_CASE(NextHopsRemoveAll)
170{
171 NextHop hop1(router1FaceUri, 10);
172 NextHop hop2(router2FaceUri, 20);
173
174 NexthopList oldHops;
175 oldHops.addNextHop(hop1);
176 oldHops.addNextHop(hop2);
177
awlanefc0b45a2025-05-07 15:51:02 -0500178 fib.update("/ndn/name", oldHops, ndn::nfd::ROUTE_FLAG_CAPTURE);
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700179 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500180
181 BOOST_REQUIRE_EQUAL(interests.size(), 2);
182 interests.clear();
183
184 NexthopList empty;
185
awlanefc0b45a2025-05-07 15:51:02 -0500186 fib.update("/ndn/name", empty, ndn::nfd::ROUTE_FLAG_CAPTURE);
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700187 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500188
189 // Should unregister faces 1 and 2 for /ndn/name
190 BOOST_CHECK_EQUAL(interests.size(), 2);
191
192 ndn::nfd::ControlParameters extractedParameters;
193 ndn::Name::Component verb;
Davide Pesavento288141a2024-02-13 17:30:35 -0500194 auto it = interests.begin();
Vince Lehman942eb7b2014-10-02 10:09:27 -0500195
196 extractRibCommandParameters(*it, verb, extractedParameters);
197
198 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
199 extractedParameters.getFaceId() == router1FaceId &&
200 verb == ndn::Name::Component("unregister"));
201
202 ++it;
203 extractRibCommandParameters(*it, verb, extractedParameters);
204
205 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
206 extractedParameters.getFaceId() == router2FaceId &&
207 verb == ndn::Name::Component("unregister"));
208}
209
210BOOST_AUTO_TEST_CASE(NextHopsMaxPrefixes)
211{
212 NextHop hop1(router1FaceUri, 10);
213 NextHop hop2(router2FaceUri, 20);
214 NextHop hop3(router3FaceUri, 30);
215
216 NexthopList hops;
217 hops.addNextHop(hop1);
218 hops.addNextHop(hop2);
219 hops.addNextHop(hop3);
220
awlanefc0b45a2025-05-07 15:51:02 -0500221 fib.update("/ndn/name", hops, ndn::nfd::ROUTE_FLAG_CAPTURE);
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700222 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500223
224 // Should only register faces 1 and 2 for /ndn/name
225 BOOST_CHECK_EQUAL(interests.size(), 2);
226
227 ndn::nfd::ControlParameters extractedParameters;
228 ndn::Name::Component verb;
Davide Pesavento288141a2024-02-13 17:30:35 -0500229 auto it = interests.begin();
Vince Lehman942eb7b2014-10-02 10:09:27 -0500230
231 extractRibCommandParameters(*it, verb, extractedParameters);
232
233 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
234 extractedParameters.getFaceId() == router1FaceId &&
235 verb == ndn::Name::Component("register"));
236
237 ++it;
238 extractRibCommandParameters(*it, verb, extractedParameters);
239
240 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
241 extractedParameters.getFaceId() == router2FaceId &&
242 verb == ndn::Name::Component("register"));
243}
244
245BOOST_AUTO_TEST_CASE(NextHopsMaxPrefixesAfterRecalculation)
246{
247 NextHop hop1(router1FaceUri, 10);
248 NextHop hop2(router2FaceUri, 20);
249
250 NexthopList hops;
251 hops.addNextHop(hop1);
252 hops.addNextHop(hop2);
253
awlanefc0b45a2025-05-07 15:51:02 -0500254 fib.update("/ndn/name", hops, ndn::nfd::ROUTE_FLAG_CAPTURE);
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700255 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500256
257 // FIB
258 // Name NextHops
259 // /ndn/name (faceId=1, cost=10), (faceId=2, cost=20)
260 BOOST_REQUIRE_EQUAL(interests.size(), 2);
261 interests.clear();
262
263 // Routing table is recalculated; a new more optimal path is found
264 NextHop hop3(router3FaceUri, 5);
265 hops.addNextHop(hop3);
266
awlanefc0b45a2025-05-07 15:51:02 -0500267 fib.update("/ndn/name", hops, ndn::nfd::ROUTE_FLAG_CAPTURE);
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700268 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500269
270 // To maintain a max 2 face requirement, face 3 should be registered and face 2 should be
271 // unregistered. Face 1 will also be re-registered.
272 //
273 // FIB
274 // Name NextHops
275 // /ndn/name (faceId=3, cost=5), (faceId=1, cost=10)
276
277 BOOST_CHECK_EQUAL(interests.size(), 3);
278
279 ndn::nfd::ControlParameters extractedParameters;
280 ndn::Name::Component verb;
Davide Pesavento288141a2024-02-13 17:30:35 -0500281 auto it = interests.begin();
Vince Lehman942eb7b2014-10-02 10:09:27 -0500282
283 extractRibCommandParameters(*it, verb, extractedParameters);
284
285 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700286 extractedParameters.getFaceId() == router1FaceId &&
Vince Lehman942eb7b2014-10-02 10:09:27 -0500287 verb == ndn::Name::Component("register"));
288
289 ++it;
290 extractRibCommandParameters(*it, verb, extractedParameters);
291
292 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700293 extractedParameters.getFaceId() == router3FaceId &&
Vince Lehman942eb7b2014-10-02 10:09:27 -0500294 verb == ndn::Name::Component("register"));
295
296 ++it;
297 extractRibCommandParameters(*it, verb, extractedParameters);
298
299 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
300 extractedParameters.getFaceId() == router2FaceId &&
301 verb == ndn::Name::Component("unregister"));
302}
303
Muktadir Chowdhury3be64662015-05-01 14:50:53 -0500304BOOST_FIXTURE_TEST_CASE(ScheduleFibEntryRefresh, FibFixture)
305{
306 ndn::Name name1("/name/1");
Ashlesh Gawande7a231c02020-06-12 20:06:44 -0700307 FibEntry fe;
308 fe.name = name1;
309 int origSeqNo = fe.seqNo;
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700310 fib.m_table.emplace(name1, std::move(fe));
Muktadir Chowdhury3be64662015-05-01 14:50:53 -0500311
awlanefc0b45a2025-05-07 15:51:02 -0500312 fib.scheduleEntryRefresh(fe, true,
313 [&] (auto& entry, bool captureFlag) { BOOST_CHECK_EQUAL(origSeqNo + 1, entry.seqNo); });
Muktadir Chowdhury3be64662015-05-01 14:50:53 -0500314 this->advanceClocks(ndn::time::milliseconds(10), 1);
Davide Pesaventod1f1df82022-03-12 16:40:37 -0500315
316 // avoid "test case [...] did not check any assertions" message from Boost.Test
317 BOOST_CHECK(true);
Muktadir Chowdhury3be64662015-05-01 14:50:53 -0500318}
319
Ashlesh Gawandee5002b32018-12-20 21:07:31 -0600320BOOST_AUTO_TEST_CASE(ShouldNotRefreshNeighborRoute) // #4799
321{
322 NextHop hop1;
323 hop1.setConnectingFaceUri(router1FaceUri);
324
325 NexthopList hops;
326 hops.addNextHop(hop1);
327
328 // Simulate update for this neighbor from name prefix table
awlanefc0b45a2025-05-07 15:51:02 -0500329 fib.update(router1Name, hops, ndn::nfd::ROUTE_FLAG_CAPTURE);
Ashlesh Gawandee5002b32018-12-20 21:07:31 -0600330 this->advanceClocks(ndn::time::seconds(1));
331
332 // Should not send the register interest
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700333 BOOST_CHECK_EQUAL(face.sentInterests.size(), 0);
334}
335
336BOOST_AUTO_TEST_CASE(PrefixWithdrawalFibUpdateBug) // #5179
337{
338 fib.setEntryRefreshTime(3600);
339 conf.setMaxFacesPerPrefix(3);
340
341 // Three adjacencies of Neu
342 Adjacent neighbor1("/ndn/memphis/router-memphis",
343 ndn::FaceUri("udp4://10.0.0.9:6363"), 21, Adjacent::STATUS_ACTIVE, 0, router1FaceId);
344 adjacencies.insert(neighbor1);
345
346 Adjacent neighbor2("/ndn/michigan/router-michigan",
347 ndn::FaceUri("udp4://10.0.0.13:6363"), 14, Adjacent::STATUS_ACTIVE, 0, router2FaceId);
348 adjacencies.insert(neighbor2);
349
350 Adjacent neighbor3("/ndn/savi/router-savi",
351 ndn::FaceUri("udp4://10.0.0.26:6363"), 15, Adjacent::STATUS_ACTIVE, 0, router3FaceId);
352 adjacencies.insert(neighbor3);
353
354 // Wustl advertises /test
355 NexthopList nhl1;
Junxiao Shi6593a432023-08-21 10:50:28 +0000356 nhl1.addNextHop(NextHop(ndn::FaceUri("udp4://10.0.0.13:6363"), 28));
357 nhl1.addNextHop(NextHop(ndn::FaceUri("udp4://10.0.0.9:6363"), 38));
358 nhl1.addNextHop(NextHop(ndn::FaceUri("udp4://10.0.0.26:6363"), 44));
awlanefc0b45a2025-05-07 15:51:02 -0500359 fib.update("/test", nhl1, ndn::nfd::ROUTE_FLAG_CAPTURE);
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700360
361 // Memphis advertises /test
362 NexthopList nhl2;
Junxiao Shi6593a432023-08-21 10:50:28 +0000363 nhl2.addNextHop(NextHop(ndn::FaceUri("udp4://10.0.0.9:6363"), 21));
364 nhl2.addNextHop(NextHop(ndn::FaceUri("udp4://10.0.0.13:6363"), 26));
365 nhl2.addNextHop(NextHop(ndn::FaceUri("udp4://10.0.0.26:6363"), 42));
awlanefc0b45a2025-05-07 15:51:02 -0500366 fib.update("/test", nhl2, ndn::nfd::ROUTE_FLAG_CAPTURE);
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700367
368 advanceClocks(10_ms);
369 face.sentInterests.clear();
370 // Memphis withdraws /test
371 // NamePrefixTable calls this saying we need to install the Wu routes
372 // instead of the existing Memphis' cheaper routes
awlanefc0b45a2025-05-07 15:51:02 -0500373 fib.update("/test", nhl1, ndn::nfd::ROUTE_FLAG_CAPTURE);
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700374
375 advanceClocks(10_ms);
376 int numRegister = 0;
377 // Do not expect any unregisters, just registers which will update the cost in NFD
378 for (const auto& i : face.sentInterests) {
Davide Pesavento8de8a8b2022-05-12 01:26:43 -0400379 if (i.getName().getPrefix(4) == "/localhost/nfd/rib/unregister") {
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700380 BOOST_CHECK(false);
381 }
382 else {
383 ++numRegister;
384 }
385 }
386 BOOST_CHECK_EQUAL(numRegister, 3);
Ashlesh Gawandee5002b32018-12-20 21:07:31 -0600387}
388
Vince Lehman942eb7b2014-10-02 10:09:27 -0500389BOOST_AUTO_TEST_SUITE_END()
390
Davide Pesavento288141a2024-02-13 17:30:35 -0500391} // namespace nlsr::tests