blob: 9da37de29206b5a1cf957d96f1e6017616069406 [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 {
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -070062 face.onSendInterest.connect([this] (const ndn::Interest& interest) {
63 static const ndn::Name localhostRegistration("/localhost/nfd/rib");
64 if (!localhostRegistration.isPrefixOf(interest.getName()))
65 return;
66
67 ndn::nfd::ControlParameters params(interest.getName().get(-5).blockFromValue());
68 if (!params.hasFaceId()) {
69 params.setFaceId(1);
70 }
71 params.setOrigin(ndn::nfd::ROUTE_ORIGIN_APP);
72 if (interest.getName().get(3) == ndn::name::Component("register")) {
73 params.setCost(0);
74 }
75
76 ndn::nfd::ControlResponse resp;
77 resp.setCode(200);
78 resp.setBody(params.wireEncode());
79
80 ndn::Data data(interest.getName());
81 data.setContent(resp.wireEncode());
82
83 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
90 extractRibCommandParameters(const ndn::Interest& interest, ndn::Name::Component& verb,
91 ndn::nfd::ControlParameters& extractedParameters)
92 {
93 static const ndn::Name commandPrefix("/localhost/nfd/rib");
Vince Lehman942eb7b2014-10-02 10:09:27 -050094
Davide Pesavento8de8a8b2022-05-12 01:26:43 -040095 const auto& name = interest.getName();
96 verb = name.at(commandPrefix.size());
97 const auto& paramComponent = name.at(commandPrefix.size() + 1);
98 extractedParameters.wireDecode(paramComponent.blockFromValue());
99 }
100
101private:
102 ndn::Scheduler m_scheduler{m_io};
103
104public:
105 ndn::util::DummyClientFace face{m_io, m_keyChain};
106
107 ConfParameter conf{face, m_keyChain};
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700108 AdjacencyList& adjacencies;
109 Fib fib;
Vince Lehman942eb7b2014-10-02 10:09:27 -0500110 std::vector<ndn::Interest>& interests;
111
112 static const ndn::Name router1Name;
113 static const ndn::Name router2Name;
114 static const ndn::Name router3Name;
115
116 static const std::string router1FaceUri;
117 static const std::string router2FaceUri;
118 static const std::string router3FaceUri;
119
120 static const uint32_t router1FaceId;
121 static const uint32_t router2FaceId;
122 static const uint32_t router3FaceId;
123};
124
125const ndn::Name FibFixture::router1Name = "/ndn/router1";
126const ndn::Name FibFixture::router2Name = "/ndn/router2";
127const ndn::Name FibFixture::router3Name = "/ndn/router3";
128
Nick Gordone9733ed2017-04-26 10:48:39 -0500129const std::string FibFixture::router1FaceUri = "udp4://10.0.0.1";
130const std::string FibFixture::router2FaceUri = "udp4://10.0.0.2";
131const std::string FibFixture::router3FaceUri = "udp4://10.0.0.3";
Vince Lehman942eb7b2014-10-02 10:09:27 -0500132
133const uint32_t FibFixture::router1FaceId = 1;
134const uint32_t FibFixture::router2FaceId = 2;
135const uint32_t FibFixture::router3FaceId = 3;
136
137BOOST_FIXTURE_TEST_SUITE(TestFib, FibFixture)
138
139BOOST_AUTO_TEST_CASE(NextHopsAdd)
140{
141 NextHop hop1(router1FaceUri, 10);
142 NextHop hop2(router2FaceUri, 20);
143
144 NexthopList hops;
145 hops.addNextHop(hop1);
146 hops.addNextHop(hop2);
147
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700148 fib.update("/ndn/name", hops);
149 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500150
151 // Should register faces 1 and 2 for /ndn/name
152 BOOST_REQUIRE_EQUAL(interests.size(), 2);
153
154 ndn::nfd::ControlParameters extractedParameters;
155 ndn::Name::Component verb;
156 std::vector<ndn::Interest>::iterator it = interests.begin();
157
158 extractRibCommandParameters(*it, verb, extractedParameters);
159
160 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
161 extractedParameters.getFaceId() == router1FaceId &&
162 verb == ndn::Name::Component("register"));
163
164 ++it;
165 extractRibCommandParameters(*it, verb, extractedParameters);
166
167 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
168 extractedParameters.getFaceId() == router2FaceId &&
169 verb == ndn::Name::Component("register"));
170}
171
Vince Lehman942eb7b2014-10-02 10:09:27 -0500172BOOST_AUTO_TEST_CASE(NextHopsNoChange)
173{
174 NextHop hop1(router1FaceUri, 10);
175 NextHop hop2(router2FaceUri, 20);
176
177 NexthopList oldHops;
178 oldHops.addNextHop(hop1);
179 oldHops.addNextHop(hop2);
180
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700181 fib.update("/ndn/name", oldHops);
182 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500183
184 BOOST_REQUIRE_EQUAL(interests.size(), 2);
185 interests.clear();
186
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700187 fib.update("/ndn/name", oldHops);
188 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500189
190 // Should register face 1 and 2 for /ndn/name
191 BOOST_REQUIRE_EQUAL(interests.size(), 2);
192
193 ndn::nfd::ControlParameters extractedParameters;
194 ndn::Name::Component verb;
195 std::vector<ndn::Interest>::iterator it = interests.begin();
196
197 extractRibCommandParameters(*it, verb, extractedParameters);
198
199 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
200 extractedParameters.getFaceId() == router1FaceId &&
201 verb == ndn::Name::Component("register"));
202
203 ++it;
204 extractRibCommandParameters(*it, verb, extractedParameters);
205
206 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
207 extractedParameters.getFaceId() == router2FaceId &&
208 verb == ndn::Name::Component("register"));
209}
210
211BOOST_AUTO_TEST_CASE(NextHopsRemoveAll)
212{
213 NextHop hop1(router1FaceUri, 10);
214 NextHop hop2(router2FaceUri, 20);
215
216 NexthopList oldHops;
217 oldHops.addNextHop(hop1);
218 oldHops.addNextHop(hop2);
219
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700220 fib.update("/ndn/name", oldHops);
221 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500222
223 BOOST_REQUIRE_EQUAL(interests.size(), 2);
224 interests.clear();
225
226 NexthopList empty;
227
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700228 fib.update("/ndn/name", empty);
229 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500230
231 // Should unregister faces 1 and 2 for /ndn/name
232 BOOST_CHECK_EQUAL(interests.size(), 2);
233
234 ndn::nfd::ControlParameters extractedParameters;
235 ndn::Name::Component verb;
236 std::vector<ndn::Interest>::iterator it = interests.begin();
237
238 extractRibCommandParameters(*it, verb, extractedParameters);
239
240 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
241 extractedParameters.getFaceId() == router1FaceId &&
242 verb == ndn::Name::Component("unregister"));
243
244 ++it;
245 extractRibCommandParameters(*it, verb, extractedParameters);
246
247 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
248 extractedParameters.getFaceId() == router2FaceId &&
249 verb == ndn::Name::Component("unregister"));
250}
251
252BOOST_AUTO_TEST_CASE(NextHopsMaxPrefixes)
253{
254 NextHop hop1(router1FaceUri, 10);
255 NextHop hop2(router2FaceUri, 20);
256 NextHop hop3(router3FaceUri, 30);
257
258 NexthopList hops;
259 hops.addNextHop(hop1);
260 hops.addNextHop(hop2);
261 hops.addNextHop(hop3);
262
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700263 fib.update("/ndn/name", hops);
264 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500265
266 // Should only register faces 1 and 2 for /ndn/name
267 BOOST_CHECK_EQUAL(interests.size(), 2);
268
269 ndn::nfd::ControlParameters extractedParameters;
270 ndn::Name::Component verb;
271 std::vector<ndn::Interest>::iterator it = interests.begin();
272
273 extractRibCommandParameters(*it, verb, extractedParameters);
274
275 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
276 extractedParameters.getFaceId() == router1FaceId &&
277 verb == ndn::Name::Component("register"));
278
279 ++it;
280 extractRibCommandParameters(*it, verb, extractedParameters);
281
282 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
283 extractedParameters.getFaceId() == router2FaceId &&
284 verb == ndn::Name::Component("register"));
285}
286
287BOOST_AUTO_TEST_CASE(NextHopsMaxPrefixesAfterRecalculation)
288{
289 NextHop hop1(router1FaceUri, 10);
290 NextHop hop2(router2FaceUri, 20);
291
292 NexthopList hops;
293 hops.addNextHop(hop1);
294 hops.addNextHop(hop2);
295
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700296 fib.update("/ndn/name", hops);
297 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500298
299 // FIB
300 // Name NextHops
301 // /ndn/name (faceId=1, cost=10), (faceId=2, cost=20)
302 BOOST_REQUIRE_EQUAL(interests.size(), 2);
303 interests.clear();
304
305 // Routing table is recalculated; a new more optimal path is found
306 NextHop hop3(router3FaceUri, 5);
307 hops.addNextHop(hop3);
308
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700309 fib.update("/ndn/name", hops);
310 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500311
312 // To maintain a max 2 face requirement, face 3 should be registered and face 2 should be
313 // unregistered. Face 1 will also be re-registered.
314 //
315 // FIB
316 // Name NextHops
317 // /ndn/name (faceId=3, cost=5), (faceId=1, cost=10)
318
319 BOOST_CHECK_EQUAL(interests.size(), 3);
320
321 ndn::nfd::ControlParameters extractedParameters;
322 ndn::Name::Component verb;
323 std::vector<ndn::Interest>::iterator it = interests.begin();
324
325 extractRibCommandParameters(*it, verb, extractedParameters);
326
327 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700328 extractedParameters.getFaceId() == router1FaceId &&
Vince Lehman942eb7b2014-10-02 10:09:27 -0500329 verb == ndn::Name::Component("register"));
330
331 ++it;
332 extractRibCommandParameters(*it, verb, extractedParameters);
333
334 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700335 extractedParameters.getFaceId() == router3FaceId &&
Vince Lehman942eb7b2014-10-02 10:09:27 -0500336 verb == ndn::Name::Component("register"));
337
338 ++it;
339 extractRibCommandParameters(*it, verb, extractedParameters);
340
341 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
342 extractedParameters.getFaceId() == router2FaceId &&
343 verb == ndn::Name::Component("unregister"));
344}
345
Muktadir Chowdhury3be64662015-05-01 14:50:53 -0500346BOOST_FIXTURE_TEST_CASE(ScheduleFibEntryRefresh, FibFixture)
347{
348 ndn::Name name1("/name/1");
Ashlesh Gawande7a231c02020-06-12 20:06:44 -0700349 FibEntry fe;
350 fe.name = name1;
351 int origSeqNo = fe.seqNo;
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700352 fib.m_table.emplace(name1, std::move(fe));
Muktadir Chowdhury3be64662015-05-01 14:50:53 -0500353
Davide Pesaventod1f1df82022-03-12 16:40:37 -0500354 fib.scheduleEntryRefresh(fe, [&] (auto& entry) { BOOST_CHECK_EQUAL(origSeqNo + 1, entry.seqNo); });
Muktadir Chowdhury3be64662015-05-01 14:50:53 -0500355 this->advanceClocks(ndn::time::milliseconds(10), 1);
Davide Pesaventod1f1df82022-03-12 16:40:37 -0500356
357 // avoid "test case [...] did not check any assertions" message from Boost.Test
358 BOOST_CHECK(true);
Muktadir Chowdhury3be64662015-05-01 14:50:53 -0500359}
360
Ashlesh Gawandee5002b32018-12-20 21:07:31 -0600361BOOST_AUTO_TEST_CASE(ShouldNotRefreshNeighborRoute) // #4799
362{
363 NextHop hop1;
364 hop1.setConnectingFaceUri(router1FaceUri);
365
366 NexthopList hops;
367 hops.addNextHop(hop1);
368
369 // Simulate update for this neighbor from name prefix table
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700370 fib.update(router1Name, hops);
Ashlesh Gawandee5002b32018-12-20 21:07:31 -0600371 this->advanceClocks(ndn::time::seconds(1));
372
373 // Should not send the register interest
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700374 BOOST_CHECK_EQUAL(face.sentInterests.size(), 0);
375}
376
377BOOST_AUTO_TEST_CASE(PrefixWithdrawalFibUpdateBug) // #5179
378{
379 fib.setEntryRefreshTime(3600);
380 conf.setMaxFacesPerPrefix(3);
381
382 // Three adjacencies of Neu
383 Adjacent neighbor1("/ndn/memphis/router-memphis",
384 ndn::FaceUri("udp4://10.0.0.9:6363"), 21, Adjacent::STATUS_ACTIVE, 0, router1FaceId);
385 adjacencies.insert(neighbor1);
386
387 Adjacent neighbor2("/ndn/michigan/router-michigan",
388 ndn::FaceUri("udp4://10.0.0.13:6363"), 14, Adjacent::STATUS_ACTIVE, 0, router2FaceId);
389 adjacencies.insert(neighbor2);
390
391 Adjacent neighbor3("/ndn/savi/router-savi",
392 ndn::FaceUri("udp4://10.0.0.26:6363"), 15, Adjacent::STATUS_ACTIVE, 0, router3FaceId);
393 adjacencies.insert(neighbor3);
394
395 // Wustl advertises /test
396 NexthopList nhl1;
397 nhl1.addNextHop(NextHop("udp4://10.0.0.13:6363", 28));
398 nhl1.addNextHop(NextHop("udp4://10.0.0.9:6363", 38));
399 nhl1.addNextHop(NextHop("udp4://10.0.0.26:6363", 44));
400 fib.update("/test", nhl1);
401
402 // Memphis advertises /test
403 NexthopList nhl2;
404 nhl2.addNextHop(NextHop("udp4://10.0.0.9:6363", 21));
405 nhl2.addNextHop(NextHop("udp4://10.0.0.13:6363", 26));
406 nhl2.addNextHop(NextHop("udp4://10.0.0.26:6363", 42));
407 fib.update("/test", nhl2);
408
409 advanceClocks(10_ms);
410 face.sentInterests.clear();
411 // Memphis withdraws /test
412 // NamePrefixTable calls this saying we need to install the Wu routes
413 // instead of the existing Memphis' cheaper routes
414 fib.update("/test", nhl1);
415
416 advanceClocks(10_ms);
417 int numRegister = 0;
418 // Do not expect any unregisters, just registers which will update the cost in NFD
419 for (const auto& i : face.sentInterests) {
Davide Pesavento8de8a8b2022-05-12 01:26:43 -0400420 if (i.getName().getPrefix(4) == "/localhost/nfd/rib/unregister") {
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700421 BOOST_CHECK(false);
422 }
423 else {
424 ++numRegister;
425 }
426 }
427 BOOST_CHECK_EQUAL(numRegister, 3);
Ashlesh Gawandee5002b32018-12-20 21:07:31 -0600428}
429
Vince Lehman942eb7b2014-10-02 10:09:27 -0500430BOOST_AUTO_TEST_SUITE_END()
431
Nick Gordonfad8e252016-08-11 14:21:38 -0500432} // namespace test
433} // namespace nlsr