blob: 5c75314ae84769056a52c2c52ba307e5b59e3325 [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 Pesaventod1f1df82022-03-12 16:40:37 -050025#include "../test-common.hpp"
26#include "../control-commands.hpp"
27
Muktadir R Chowdhuryc69da0a2015-12-18 13:24:38 -060028#include <ndn-cxx/util/dummy-client-face.hpp>
29
Vince Lehman942eb7b2014-10-02 10:09:27 -050030namespace nlsr {
31namespace test {
32
Muktadir Chowdhury3be64662015-05-01 14:50:53 -050033class FibFixture : public UnitTestTimeFixture
Vince Lehman942eb7b2014-10-02 10:09:27 -050034{
35public:
36 FibFixture()
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -070037 : face(m_ioService, m_keyChain)
38 , conf(face, m_keyChain)
39 , adjacencies(conf.getAdjacencyList())
40 , fib(face, m_scheduler, adjacencies, conf, m_keyChain)
41 , interests(face.sentInterests)
Vince Lehman942eb7b2014-10-02 10:09:27 -050042 {
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -070043 enableRegistrationReplyWithFaceId();
44 advanceClocks(1_s);
45
Muktadir Chowdhuryf04f9892017-08-20 20:42:56 -050046 Adjacent neighbor1(router1Name, ndn::FaceUri(router1FaceUri), 0, Adjacent::STATUS_ACTIVE, 0, router1FaceId);
Vince Lehman942eb7b2014-10-02 10:09:27 -050047 adjacencies.insert(neighbor1);
48
Muktadir Chowdhuryf04f9892017-08-20 20:42:56 -050049 Adjacent neighbor2(router2Name, ndn::FaceUri(router2FaceUri), 0, Adjacent::STATUS_ACTIVE, 0, router2FaceId);
Vince Lehman942eb7b2014-10-02 10:09:27 -050050 adjacencies.insert(neighbor2);
51
Muktadir Chowdhuryf04f9892017-08-20 20:42:56 -050052 Adjacent neighbor3(router3Name, ndn::FaceUri(router3FaceUri), 0, Adjacent::STATUS_ACTIVE, 0, router3FaceId);
Vince Lehman942eb7b2014-10-02 10:09:27 -050053 adjacencies.insert(neighbor3);
54
55 conf.setMaxFacesPerPrefix(2);
56
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -070057 fib.setEntryRefreshTime(1);
58 }
59
60 void
61 enableRegistrationReplyWithFaceId() {
62 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
89public:
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -070090 ndn::util::DummyClientFace face;
Vince Lehman942eb7b2014-10-02 10:09:27 -050091
Vince Lehman942eb7b2014-10-02 10:09:27 -050092 ConfParameter conf;
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -070093 AdjacencyList& adjacencies;
94 Fib fib;
Vince Lehman942eb7b2014-10-02 10:09:27 -050095 std::vector<ndn::Interest>& interests;
96
97 static const ndn::Name router1Name;
98 static const ndn::Name router2Name;
99 static const ndn::Name router3Name;
100
101 static const std::string router1FaceUri;
102 static const std::string router2FaceUri;
103 static const std::string router3FaceUri;
104
105 static const uint32_t router1FaceId;
106 static const uint32_t router2FaceId;
107 static const uint32_t router3FaceId;
108};
109
110const ndn::Name FibFixture::router1Name = "/ndn/router1";
111const ndn::Name FibFixture::router2Name = "/ndn/router2";
112const ndn::Name FibFixture::router3Name = "/ndn/router3";
113
Nick Gordone9733ed2017-04-26 10:48:39 -0500114const std::string FibFixture::router1FaceUri = "udp4://10.0.0.1";
115const std::string FibFixture::router2FaceUri = "udp4://10.0.0.2";
116const std::string FibFixture::router3FaceUri = "udp4://10.0.0.3";
Vince Lehman942eb7b2014-10-02 10:09:27 -0500117
118const uint32_t FibFixture::router1FaceId = 1;
119const uint32_t FibFixture::router2FaceId = 2;
120const uint32_t FibFixture::router3FaceId = 3;
121
122BOOST_FIXTURE_TEST_SUITE(TestFib, FibFixture)
123
124BOOST_AUTO_TEST_CASE(NextHopsAdd)
125{
126 NextHop hop1(router1FaceUri, 10);
127 NextHop hop2(router2FaceUri, 20);
128
129 NexthopList hops;
130 hops.addNextHop(hop1);
131 hops.addNextHop(hop2);
132
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700133 fib.update("/ndn/name", hops);
134 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500135
136 // Should register faces 1 and 2 for /ndn/name
137 BOOST_REQUIRE_EQUAL(interests.size(), 2);
138
139 ndn::nfd::ControlParameters extractedParameters;
140 ndn::Name::Component verb;
141 std::vector<ndn::Interest>::iterator it = interests.begin();
142
143 extractRibCommandParameters(*it, verb, extractedParameters);
144
145 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
146 extractedParameters.getFaceId() == router1FaceId &&
147 verb == ndn::Name::Component("register"));
148
149 ++it;
150 extractRibCommandParameters(*it, verb, extractedParameters);
151
152 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
153 extractedParameters.getFaceId() == router2FaceId &&
154 verb == ndn::Name::Component("register"));
155}
156
Vince Lehman942eb7b2014-10-02 10:09:27 -0500157BOOST_AUTO_TEST_CASE(NextHopsNoChange)
158{
159 NextHop hop1(router1FaceUri, 10);
160 NextHop hop2(router2FaceUri, 20);
161
162 NexthopList oldHops;
163 oldHops.addNextHop(hop1);
164 oldHops.addNextHop(hop2);
165
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700166 fib.update("/ndn/name", oldHops);
167 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500168
169 BOOST_REQUIRE_EQUAL(interests.size(), 2);
170 interests.clear();
171
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700172 fib.update("/ndn/name", oldHops);
173 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500174
175 // Should register face 1 and 2 for /ndn/name
176 BOOST_REQUIRE_EQUAL(interests.size(), 2);
177
178 ndn::nfd::ControlParameters extractedParameters;
179 ndn::Name::Component verb;
180 std::vector<ndn::Interest>::iterator it = interests.begin();
181
182 extractRibCommandParameters(*it, verb, extractedParameters);
183
184 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
185 extractedParameters.getFaceId() == router1FaceId &&
186 verb == ndn::Name::Component("register"));
187
188 ++it;
189 extractRibCommandParameters(*it, verb, extractedParameters);
190
191 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
192 extractedParameters.getFaceId() == router2FaceId &&
193 verb == ndn::Name::Component("register"));
194}
195
196BOOST_AUTO_TEST_CASE(NextHopsRemoveAll)
197{
198 NextHop hop1(router1FaceUri, 10);
199 NextHop hop2(router2FaceUri, 20);
200
201 NexthopList oldHops;
202 oldHops.addNextHop(hop1);
203 oldHops.addNextHop(hop2);
204
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700205 fib.update("/ndn/name", oldHops);
206 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500207
208 BOOST_REQUIRE_EQUAL(interests.size(), 2);
209 interests.clear();
210
211 NexthopList empty;
212
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700213 fib.update("/ndn/name", empty);
214 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500215
216 // Should unregister faces 1 and 2 for /ndn/name
217 BOOST_CHECK_EQUAL(interests.size(), 2);
218
219 ndn::nfd::ControlParameters extractedParameters;
220 ndn::Name::Component verb;
221 std::vector<ndn::Interest>::iterator it = interests.begin();
222
223 extractRibCommandParameters(*it, verb, extractedParameters);
224
225 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
226 extractedParameters.getFaceId() == router1FaceId &&
227 verb == ndn::Name::Component("unregister"));
228
229 ++it;
230 extractRibCommandParameters(*it, verb, extractedParameters);
231
232 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
233 extractedParameters.getFaceId() == router2FaceId &&
234 verb == ndn::Name::Component("unregister"));
235}
236
237BOOST_AUTO_TEST_CASE(NextHopsMaxPrefixes)
238{
239 NextHop hop1(router1FaceUri, 10);
240 NextHop hop2(router2FaceUri, 20);
241 NextHop hop3(router3FaceUri, 30);
242
243 NexthopList hops;
244 hops.addNextHop(hop1);
245 hops.addNextHop(hop2);
246 hops.addNextHop(hop3);
247
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700248 fib.update("/ndn/name", hops);
249 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500250
251 // Should only register faces 1 and 2 for /ndn/name
252 BOOST_CHECK_EQUAL(interests.size(), 2);
253
254 ndn::nfd::ControlParameters extractedParameters;
255 ndn::Name::Component verb;
256 std::vector<ndn::Interest>::iterator it = interests.begin();
257
258 extractRibCommandParameters(*it, verb, extractedParameters);
259
260 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
261 extractedParameters.getFaceId() == router1FaceId &&
262 verb == ndn::Name::Component("register"));
263
264 ++it;
265 extractRibCommandParameters(*it, verb, extractedParameters);
266
267 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
268 extractedParameters.getFaceId() == router2FaceId &&
269 verb == ndn::Name::Component("register"));
270}
271
272BOOST_AUTO_TEST_CASE(NextHopsMaxPrefixesAfterRecalculation)
273{
274 NextHop hop1(router1FaceUri, 10);
275 NextHop hop2(router2FaceUri, 20);
276
277 NexthopList hops;
278 hops.addNextHop(hop1);
279 hops.addNextHop(hop2);
280
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700281 fib.update("/ndn/name", hops);
282 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500283
284 // FIB
285 // Name NextHops
286 // /ndn/name (faceId=1, cost=10), (faceId=2, cost=20)
287 BOOST_REQUIRE_EQUAL(interests.size(), 2);
288 interests.clear();
289
290 // Routing table is recalculated; a new more optimal path is found
291 NextHop hop3(router3FaceUri, 5);
292 hops.addNextHop(hop3);
293
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700294 fib.update("/ndn/name", hops);
295 face.processEvents(ndn::time::milliseconds(-1));
Vince Lehman942eb7b2014-10-02 10:09:27 -0500296
297 // To maintain a max 2 face requirement, face 3 should be registered and face 2 should be
298 // unregistered. Face 1 will also be re-registered.
299 //
300 // FIB
301 // Name NextHops
302 // /ndn/name (faceId=3, cost=5), (faceId=1, cost=10)
303
304 BOOST_CHECK_EQUAL(interests.size(), 3);
305
306 ndn::nfd::ControlParameters extractedParameters;
307 ndn::Name::Component verb;
308 std::vector<ndn::Interest>::iterator it = interests.begin();
309
310 extractRibCommandParameters(*it, verb, extractedParameters);
311
312 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700313 extractedParameters.getFaceId() == router1FaceId &&
Vince Lehman942eb7b2014-10-02 10:09:27 -0500314 verb == ndn::Name::Component("register"));
315
316 ++it;
317 extractRibCommandParameters(*it, verb, extractedParameters);
318
319 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700320 extractedParameters.getFaceId() == router3FaceId &&
Vince Lehman942eb7b2014-10-02 10:09:27 -0500321 verb == ndn::Name::Component("register"));
322
323 ++it;
324 extractRibCommandParameters(*it, verb, extractedParameters);
325
326 BOOST_CHECK(extractedParameters.getName() == "/ndn/name" &&
327 extractedParameters.getFaceId() == router2FaceId &&
328 verb == ndn::Name::Component("unregister"));
329}
330
Muktadir Chowdhury3be64662015-05-01 14:50:53 -0500331BOOST_FIXTURE_TEST_CASE(ScheduleFibEntryRefresh, FibFixture)
332{
333 ndn::Name name1("/name/1");
Ashlesh Gawande7a231c02020-06-12 20:06:44 -0700334 FibEntry fe;
335 fe.name = name1;
336 int origSeqNo = fe.seqNo;
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700337 fib.m_table.emplace(name1, std::move(fe));
Muktadir Chowdhury3be64662015-05-01 14:50:53 -0500338
Davide Pesaventod1f1df82022-03-12 16:40:37 -0500339 fib.scheduleEntryRefresh(fe, [&] (auto& entry) { BOOST_CHECK_EQUAL(origSeqNo + 1, entry.seqNo); });
Muktadir Chowdhury3be64662015-05-01 14:50:53 -0500340 this->advanceClocks(ndn::time::milliseconds(10), 1);
Davide Pesaventod1f1df82022-03-12 16:40:37 -0500341
342 // avoid "test case [...] did not check any assertions" message from Boost.Test
343 BOOST_CHECK(true);
Muktadir Chowdhury3be64662015-05-01 14:50:53 -0500344}
345
Ashlesh Gawandee5002b32018-12-20 21:07:31 -0600346BOOST_AUTO_TEST_CASE(ShouldNotRefreshNeighborRoute) // #4799
347{
348 NextHop hop1;
349 hop1.setConnectingFaceUri(router1FaceUri);
350
351 NexthopList hops;
352 hops.addNextHop(hop1);
353
354 // Simulate update for this neighbor from name prefix table
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700355 fib.update(router1Name, hops);
Ashlesh Gawandee5002b32018-12-20 21:07:31 -0600356 this->advanceClocks(ndn::time::seconds(1));
357
358 // Should not send the register interest
Ashlesh Gawande6f0f35d2021-08-21 23:52:14 -0700359 BOOST_CHECK_EQUAL(face.sentInterests.size(), 0);
360}
361
362BOOST_AUTO_TEST_CASE(PrefixWithdrawalFibUpdateBug) // #5179
363{
364 fib.setEntryRefreshTime(3600);
365 conf.setMaxFacesPerPrefix(3);
366
367 // Three adjacencies of Neu
368 Adjacent neighbor1("/ndn/memphis/router-memphis",
369 ndn::FaceUri("udp4://10.0.0.9:6363"), 21, Adjacent::STATUS_ACTIVE, 0, router1FaceId);
370 adjacencies.insert(neighbor1);
371
372 Adjacent neighbor2("/ndn/michigan/router-michigan",
373 ndn::FaceUri("udp4://10.0.0.13:6363"), 14, Adjacent::STATUS_ACTIVE, 0, router2FaceId);
374 adjacencies.insert(neighbor2);
375
376 Adjacent neighbor3("/ndn/savi/router-savi",
377 ndn::FaceUri("udp4://10.0.0.26:6363"), 15, Adjacent::STATUS_ACTIVE, 0, router3FaceId);
378 adjacencies.insert(neighbor3);
379
380 // Wustl advertises /test
381 NexthopList nhl1;
382 nhl1.addNextHop(NextHop("udp4://10.0.0.13:6363", 28));
383 nhl1.addNextHop(NextHop("udp4://10.0.0.9:6363", 38));
384 nhl1.addNextHop(NextHop("udp4://10.0.0.26:6363", 44));
385 fib.update("/test", nhl1);
386
387 // Memphis advertises /test
388 NexthopList nhl2;
389 nhl2.addNextHop(NextHop("udp4://10.0.0.9:6363", 21));
390 nhl2.addNextHop(NextHop("udp4://10.0.0.13:6363", 26));
391 nhl2.addNextHop(NextHop("udp4://10.0.0.26:6363", 42));
392 fib.update("/test", nhl2);
393
394 advanceClocks(10_ms);
395 face.sentInterests.clear();
396 // Memphis withdraws /test
397 // NamePrefixTable calls this saying we need to install the Wu routes
398 // instead of the existing Memphis' cheaper routes
399 fib.update("/test", nhl1);
400
401 advanceClocks(10_ms);
402 int numRegister = 0;
403 // Do not expect any unregisters, just registers which will update the cost in NFD
404 for (const auto& i : face.sentInterests) {
405 if (i.getName().getPrefix(4) == "/localhost/nfd/rib/unregister/") {
406 BOOST_CHECK(false);
407 }
408 else {
409 ++numRegister;
410 }
411 }
412 BOOST_CHECK_EQUAL(numRegister, 3);
Ashlesh Gawandee5002b32018-12-20 21:07:31 -0600413}
414
Vince Lehman942eb7b2014-10-02 10:09:27 -0500415BOOST_AUTO_TEST_SUITE_END()
416
Nick Gordonfad8e252016-08-11 14:21:38 -0500417} // namespace test
418} // namespace nlsr