blob: a902eb7e53b1c2a2cf00acc2d085fe622783eaab [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/*
Davide Pesaventod1f1df82022-03-12 16:40:37 -05003 * Copyright (c) 2014-2022, 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
Vince Lehman942eb7b2014-10-02 10:09:27 -050031namespace nlsr {
32namespace test {
33
Davide Pesavento8de8a8b2022-05-12 01:26:43 -040034class FibFixture : public IoKeyChainFixture
Vince Lehman942eb7b2014-10-02 10:09:27 -050035{
36public:
37 FibFixture()
Davide Pesavento8de8a8b2022-05-12 01:26:43 -040038 : adjacencies(conf.getAdjacencyList())
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -070039 , fib(face, m_scheduler, adjacencies, conf, m_keyChain)
40 , interests(face.sentInterests)
Vince Lehman942eb7b2014-10-02 10:09:27 -050041 {
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -070042 enableRegistrationReplyWithFaceId();
43 advanceClocks(1_s);
44
Muktadir Chowdhuryf04f9892017-08-20 20:42:56 -050045 Adjacent neighbor1(router1Name, ndn::FaceUri(router1FaceUri), 0, Adjacent::STATUS_ACTIVE, 0, router1FaceId);
Vince Lehman942eb7b2014-10-02 10:09:27 -050046 adjacencies.insert(neighbor1);
47
Muktadir Chowdhuryf04f9892017-08-20 20:42:56 -050048 Adjacent neighbor2(router2Name, ndn::FaceUri(router2FaceUri), 0, Adjacent::STATUS_ACTIVE, 0, router2FaceId);
Vince Lehman942eb7b2014-10-02 10:09:27 -050049 adjacencies.insert(neighbor2);
50
Muktadir Chowdhuryf04f9892017-08-20 20:42:56 -050051 Adjacent neighbor3(router3Name, ndn::FaceUri(router3FaceUri), 0, Adjacent::STATUS_ACTIVE, 0, router3FaceId);
Vince Lehman942eb7b2014-10-02 10:09:27 -050052 adjacencies.insert(neighbor3);
53
54 conf.setMaxFacesPerPrefix(2);
55
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -070056 fib.setEntryRefreshTime(1);
57 }
58
59 void
Davide Pesavento8de8a8b2022-05-12 01:26:43 -040060 enableRegistrationReplyWithFaceId()
61 {
Davide Pesavento69904fc2022-10-14 09:45:34 -040062 face.onSendInterest.connect([this] (const auto& interest) {
63 if (!RIB_COMMAND_PREFIX.isPrefixOf(interest.getName()))
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -070064 return;
65
Davide Pesavento69904fc2022-10-14 09:45:34 -040066 ndn::name::Component verb;
67 ndn::nfd::ControlParameters params;
68 extractRibCommandParameters(interest, verb, params);
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -070069 if (!params.hasFaceId()) {
70 params.setFaceId(1);
71 }
72 params.setOrigin(ndn::nfd::ROUTE_ORIGIN_APP);
Davide Pesavento69904fc2022-10-14 09:45:34 -040073 if (verb == ndn::name::Component("register")) {
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -070074 params.setCost(0);
75 }
76
77 ndn::nfd::ControlResponse resp;
78 resp.setCode(200);
79 resp.setBody(params.wireEncode());
80
81 ndn::Data data(interest.getName());
82 data.setContent(resp.wireEncode());
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -070083 m_keyChain.sign(data, ndn::security::SigningInfo(ndn::security::SigningInfo::SIGNER_TYPE_SHA256));
84
85 face.getIoService().post([this, data] { face.receive(data); });
86 });
Vince Lehman942eb7b2014-10-02 10:09:27 -050087 }
88
Davide Pesavento8de8a8b2022-05-12 01:26:43 -040089 static void
Davide Pesavento69904fc2022-10-14 09:45:34 -040090 extractRibCommandParameters(const ndn::Interest& interest,
91 ndn::Name::Component& verb,
92 ndn::nfd::ControlParameters& params)
Davide Pesavento8de8a8b2022-05-12 01:26:43 -040093 {
Davide Pesavento8de8a8b2022-05-12 01:26:43 -040094 const auto& name = interest.getName();
Davide Pesavento69904fc2022-10-14 09:45:34 -040095 verb = name.at(RIB_COMMAND_PREFIX.size());
96 params.wireDecode(name.at(RIB_COMMAND_PREFIX.size() + 1).blockFromValue());
Davide Pesavento8de8a8b2022-05-12 01:26:43 -040097 }
98
99private:
Davide Pesavento69904fc2022-10-14 09:45:34 -0400100 static inline const ndn::Name RIB_COMMAND_PREFIX{"/localhost/nfd/rib"};
101
Davide Pesavento8de8a8b2022-05-12 01:26:43 -0400102 ndn::Scheduler m_scheduler{m_io};
103
104public:
105 ndn::util::DummyClientFace face{m_io, m_keyChain};
Davide Pesavento8de8a8b2022-05-12 01:26:43 -0400106 ConfParameter conf{face, m_keyChain};
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700107 AdjacencyList& adjacencies;
108 Fib fib;
Vince Lehman942eb7b2014-10-02 10:09:27 -0500109 std::vector<ndn::Interest>& interests;
110
111 static const ndn::Name router1Name;
112 static const ndn::Name router2Name;
113 static const ndn::Name router3Name;
114
115 static const std::string router1FaceUri;
116 static const std::string router2FaceUri;
117 static const std::string router3FaceUri;
118
119 static const uint32_t router1FaceId;
120 static const uint32_t router2FaceId;
121 static const uint32_t router3FaceId;
122};
123
124const ndn::Name FibFixture::router1Name = "/ndn/router1";
125const ndn::Name FibFixture::router2Name = "/ndn/router2";
126const ndn::Name FibFixture::router3Name = "/ndn/router3";
127
Nick Gordone9733ed2017-04-26 10:48:39 -0500128const std::string FibFixture::router1FaceUri = "udp4://10.0.0.1";
129const std::string FibFixture::router2FaceUri = "udp4://10.0.0.2";
130const std::string FibFixture::router3FaceUri = "udp4://10.0.0.3";
Vince Lehman942eb7b2014-10-02 10:09:27 -0500131
132const uint32_t FibFixture::router1FaceId = 1;
133const uint32_t FibFixture::router2FaceId = 2;
134const uint32_t FibFixture::router3FaceId = 3;
135
136BOOST_FIXTURE_TEST_SUITE(TestFib, FibFixture)
137
138BOOST_AUTO_TEST_CASE(NextHopsAdd)
139{
140 NextHop hop1(router1FaceUri, 10);
141 NextHop hop2(router2FaceUri, 20);
142
143 NexthopList hops;
144 hops.addNextHop(hop1);
145 hops.addNextHop(hop2);
146
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700147 fib.update("/ndn/name", hops);
148 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500149
150 // Should register faces 1 and 2 for /ndn/name
151 BOOST_REQUIRE_EQUAL(interests.size(), 2);
152
153 ndn::nfd::ControlParameters extractedParameters;
154 ndn::Name::Component verb;
155 std::vector<ndn::Interest>::iterator it = interests.begin();
156
157 extractRibCommandParameters(*it, verb, extractedParameters);
158
159 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
160 extractedParameters.getFaceId() == router1FaceId &&
161 verb == ndn::Name::Component("register"));
162
163 ++it;
164 extractRibCommandParameters(*it, verb, extractedParameters);
165
166 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
167 extractedParameters.getFaceId() == router2FaceId &&
168 verb == ndn::Name::Component("register"));
169}
170
Vince Lehman942eb7b2014-10-02 10:09:27 -0500171BOOST_AUTO_TEST_CASE(NextHopsNoChange)
172{
173 NextHop hop1(router1FaceUri, 10);
174 NextHop hop2(router2FaceUri, 20);
175
176 NexthopList oldHops;
177 oldHops.addNextHop(hop1);
178 oldHops.addNextHop(hop2);
179
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700180 fib.update("/ndn/name", oldHops);
181 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500182
183 BOOST_REQUIRE_EQUAL(interests.size(), 2);
184 interests.clear();
185
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700186 fib.update("/ndn/name", oldHops);
187 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500188
189 // Should register face 1 and 2 for /ndn/name
190 BOOST_REQUIRE_EQUAL(interests.size(), 2);
191
192 ndn::nfd::ControlParameters extractedParameters;
193 ndn::Name::Component verb;
194 std::vector<ndn::Interest>::iterator it = interests.begin();
195
196 extractRibCommandParameters(*it, verb, extractedParameters);
197
198 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
199 extractedParameters.getFaceId() == router1FaceId &&
200 verb == ndn::Name::Component("register"));
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("register"));
208}
209
210BOOST_AUTO_TEST_CASE(NextHopsRemoveAll)
211{
212 NextHop hop1(router1FaceUri, 10);
213 NextHop hop2(router2FaceUri, 20);
214
215 NexthopList oldHops;
216 oldHops.addNextHop(hop1);
217 oldHops.addNextHop(hop2);
218
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700219 fib.update("/ndn/name", oldHops);
220 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500221
222 BOOST_REQUIRE_EQUAL(interests.size(), 2);
223 interests.clear();
224
225 NexthopList empty;
226
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700227 fib.update("/ndn/name", empty);
228 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500229
230 // Should unregister faces 1 and 2 for /ndn/name
231 BOOST_CHECK_EQUAL(interests.size(), 2);
232
233 ndn::nfd::ControlParameters extractedParameters;
234 ndn::Name::Component verb;
235 std::vector<ndn::Interest>::iterator it = interests.begin();
236
237 extractRibCommandParameters(*it, verb, extractedParameters);
238
239 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
240 extractedParameters.getFaceId() == router1FaceId &&
241 verb == ndn::Name::Component("unregister"));
242
243 ++it;
244 extractRibCommandParameters(*it, verb, extractedParameters);
245
246 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
247 extractedParameters.getFaceId() == router2FaceId &&
248 verb == ndn::Name::Component("unregister"));
249}
250
251BOOST_AUTO_TEST_CASE(NextHopsMaxPrefixes)
252{
253 NextHop hop1(router1FaceUri, 10);
254 NextHop hop2(router2FaceUri, 20);
255 NextHop hop3(router3FaceUri, 30);
256
257 NexthopList hops;
258 hops.addNextHop(hop1);
259 hops.addNextHop(hop2);
260 hops.addNextHop(hop3);
261
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700262 fib.update("/ndn/name", hops);
263 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500264
265 // Should only register faces 1 and 2 for /ndn/name
266 BOOST_CHECK_EQUAL(interests.size(), 2);
267
268 ndn::nfd::ControlParameters extractedParameters;
269 ndn::Name::Component verb;
270 std::vector<ndn::Interest>::iterator it = interests.begin();
271
272 extractRibCommandParameters(*it, verb, extractedParameters);
273
274 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
275 extractedParameters.getFaceId() == router1FaceId &&
276 verb == ndn::Name::Component("register"));
277
278 ++it;
279 extractRibCommandParameters(*it, verb, extractedParameters);
280
281 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
282 extractedParameters.getFaceId() == router2FaceId &&
283 verb == ndn::Name::Component("register"));
284}
285
286BOOST_AUTO_TEST_CASE(NextHopsMaxPrefixesAfterRecalculation)
287{
288 NextHop hop1(router1FaceUri, 10);
289 NextHop hop2(router2FaceUri, 20);
290
291 NexthopList hops;
292 hops.addNextHop(hop1);
293 hops.addNextHop(hop2);
294
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700295 fib.update("/ndn/name", hops);
296 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500297
298 // FIB
299 // Name NextHops
300 // /ndn/name (faceId=1, cost=10), (faceId=2, cost=20)
301 BOOST_REQUIRE_EQUAL(interests.size(), 2);
302 interests.clear();
303
304 // Routing table is recalculated; a new more optimal path is found
305 NextHop hop3(router3FaceUri, 5);
306 hops.addNextHop(hop3);
307
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700308 fib.update("/ndn/name", hops);
309 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500310
311 // To maintain a max 2 face requirement, face 3 should be registered and face 2 should be
312 // unregistered. Face 1 will also be re-registered.
313 //
314 // FIB
315 // Name NextHops
316 // /ndn/name (faceId=3, cost=5), (faceId=1, cost=10)
317
318 BOOST_CHECK_EQUAL(interests.size(), 3);
319
320 ndn::nfd::ControlParameters extractedParameters;
321 ndn::Name::Component verb;
322 std::vector<ndn::Interest>::iterator it = interests.begin();
323
324 extractRibCommandParameters(*it, verb, extractedParameters);
325
326 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700327 extractedParameters.getFaceId() == router1FaceId &&
Vince Lehman942eb7b2014-10-02 10:09:27 -0500328 verb == ndn::Name::Component("register"));
329
330 ++it;
331 extractRibCommandParameters(*it, verb, extractedParameters);
332
333 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700334 extractedParameters.getFaceId() == router3FaceId &&
Vince Lehman942eb7b2014-10-02 10:09:27 -0500335 verb == ndn::Name::Component("register"));
336
337 ++it;
338 extractRibCommandParameters(*it, verb, extractedParameters);
339
340 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
341 extractedParameters.getFaceId() == router2FaceId &&
342 verb == ndn::Name::Component("unregister"));
343}
344
Muktadir Chowdhury3be64662015-05-01 14:50:53 -0500345BOOST_FIXTURE_TEST_CASE(ScheduleFibEntryRefresh, FibFixture)
346{
347 ndn::Name name1("/name/1");
Ashlesh Gawande7a231c02020-06-12 20:06:44 -0700348 FibEntry fe;
349 fe.name = name1;
350 int origSeqNo = fe.seqNo;
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700351 fib.m_table.emplace(name1, std::move(fe));
Muktadir Chowdhury3be64662015-05-01 14:50:53 -0500352
Davide Pesaventod1f1df82022-03-12 16:40:37 -0500353 fib.scheduleEntryRefresh(fe, [&] (auto& entry) { BOOST_CHECK_EQUAL(origSeqNo + 1, entry.seqNo); });
Muktadir Chowdhury3be64662015-05-01 14:50:53 -0500354 this->advanceClocks(ndn::time::milliseconds(10), 1);
Davide Pesaventod1f1df82022-03-12 16:40:37 -0500355
356 // avoid "test case [...] did not check any assertions" message from Boost.Test
357 BOOST_CHECK(true);
Muktadir Chowdhury3be64662015-05-01 14:50:53 -0500358}
359
Ashlesh Gawandee5002b32018-12-20 21:07:31 -0600360BOOST_AUTO_TEST_CASE(ShouldNotRefreshNeighborRoute) // #4799
361{
362 NextHop hop1;
363 hop1.setConnectingFaceUri(router1FaceUri);
364
365 NexthopList hops;
366 hops.addNextHop(hop1);
367
368 // Simulate update for this neighbor from name prefix table
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700369 fib.update(router1Name, hops);
Ashlesh Gawandee5002b32018-12-20 21:07:31 -0600370 this->advanceClocks(ndn::time::seconds(1));
371
372 // Should not send the register interest
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700373 BOOST_CHECK_EQUAL(face.sentInterests.size(), 0);
374}
375
376BOOST_AUTO_TEST_CASE(PrefixWithdrawalFibUpdateBug) // #5179
377{
378 fib.setEntryRefreshTime(3600);
379 conf.setMaxFacesPerPrefix(3);
380
381 // Three adjacencies of Neu
382 Adjacent neighbor1("/ndn/memphis/router-memphis",
383 ndn::FaceUri("udp4://10.0.0.9:6363"), 21, Adjacent::STATUS_ACTIVE, 0, router1FaceId);
384 adjacencies.insert(neighbor1);
385
386 Adjacent neighbor2("/ndn/michigan/router-michigan",
387 ndn::FaceUri("udp4://10.0.0.13:6363"), 14, Adjacent::STATUS_ACTIVE, 0, router2FaceId);
388 adjacencies.insert(neighbor2);
389
390 Adjacent neighbor3("/ndn/savi/router-savi",
391 ndn::FaceUri("udp4://10.0.0.26:6363"), 15, Adjacent::STATUS_ACTIVE, 0, router3FaceId);
392 adjacencies.insert(neighbor3);
393
394 // Wustl advertises /test
395 NexthopList nhl1;
396 nhl1.addNextHop(NextHop("udp4://10.0.0.13:6363", 28));
397 nhl1.addNextHop(NextHop("udp4://10.0.0.9:6363", 38));
398 nhl1.addNextHop(NextHop("udp4://10.0.0.26:6363", 44));
399 fib.update("/test", nhl1);
400
401 // Memphis advertises /test
402 NexthopList nhl2;
403 nhl2.addNextHop(NextHop("udp4://10.0.0.9:6363", 21));
404 nhl2.addNextHop(NextHop("udp4://10.0.0.13:6363", 26));
405 nhl2.addNextHop(NextHop("udp4://10.0.0.26:6363", 42));
406 fib.update("/test", nhl2);
407
408 advanceClocks(10_ms);
409 face.sentInterests.clear();
410 // Memphis withdraws /test
411 // NamePrefixTable calls this saying we need to install the Wu routes
412 // instead of the existing Memphis' cheaper routes
413 fib.update("/test", nhl1);
414
415 advanceClocks(10_ms);
416 int numRegister = 0;
417 // Do not expect any unregisters, just registers which will update the cost in NFD
418 for (const auto& i : face.sentInterests) {
Davide Pesavento8de8a8b2022-05-12 01:26:43 -0400419 if (i.getName().getPrefix(4) == "/localhost/nfd/rib/unregister") {
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700420 BOOST_CHECK(false);
421 }
422 else {
423 ++numRegister;
424 }
425 }
426 BOOST_CHECK_EQUAL(numRegister, 3);
Ashlesh Gawandee5002b32018-12-20 21:07:31 -0600427}
428
Vince Lehman942eb7b2014-10-02 10:09:27 -0500429BOOST_AUTO_TEST_SUITE_END()
430
Nick Gordonfad8e252016-08-11 14:21:38 -0500431} // namespace test
432} // namespace nlsr