Recalculate routing table after face destroy event
refs: #2635
Change-Id: I7abbb638515af4a55c4241c4242a496a8cf8ca88
diff --git a/src/nlsr.cpp b/src/nlsr.cpp
index eb06be0..c77cbf8 100644
--- a/src/nlsr.cpp
+++ b/src/nlsr.cpp
@@ -277,15 +277,25 @@
void
Nlsr::onFaceEventNotification(const ndn::nfd::FaceEventNotification& faceEventNotification)
{
+ _LOG_TRACE("Nlsr::onFaceEventNotification called");
ndn::nfd::FaceEventKind kind = faceEventNotification.getKind();
- _LOG_DEBUG("Nlsr::onFaceEventNotification called");
+
if (kind == ndn::nfd::FACE_EVENT_DESTROYED) {
uint64_t faceId = faceEventNotification.getFaceId();
- Adjacent *adjacent = m_adjacencyList.findAdjacent(faceId);
- if (adjacent != 0) {
- _LOG_DEBUG("Face to " << adjacent->getName() << " with face id: "
- << faceId << " deleted");
+
+ Adjacent* adjacent = m_adjacencyList.findAdjacent(faceId);
+
+ if (adjacent != nullptr) {
+ _LOG_DEBUG("Face to " << adjacent->getName() << " with face id: " << faceId << " destroyed");
+
adjacent->setFaceId(0);
+ adjacent->setStatus(Adjacent::STATUS_INACTIVE);
+
+ // A new adjacency LSA cannot be built until the neighbor is marked INACTIVE and
+ // has met the HELLO retry threshold
+ adjacent->setInterestTimedOutNo(m_confParam.getInterestRetryNumber());
+
+ m_nlsrLsdb.scheduleAdjLsaBuild();
}
}
}
diff --git a/tests/test-common.hpp b/tests/test-common.hpp
index 7bb4c20..5731292 100644
--- a/tests/test-common.hpp
+++ b/tests/test-common.hpp
@@ -29,6 +29,7 @@
#include <boost/test/unit_test.hpp>
#include <ndn-cxx/util/scheduler.hpp>
+#include <ndn-cxx/util/time-unit-test-clock.hpp>
namespace nlsr {
namespace test {
@@ -46,6 +47,41 @@
ndn::Scheduler g_scheduler;
};
+class UnitTestTimeFixture : public BaseFixture
+{
+protected:
+ UnitTestTimeFixture()
+ : steadyClock(make_shared<ndn::time::UnitTestSteadyClock>())
+ , systemClock(make_shared<ndn::time::UnitTestSystemClock>())
+ {
+ ndn::time::setCustomClocks(steadyClock, systemClock);
+ }
+
+ ~UnitTestTimeFixture()
+ {
+ ndn::time::setCustomClocks(nullptr, nullptr);
+ }
+
+ void
+ advanceClocks(const ndn::time::nanoseconds& tick, size_t nTicks = 1)
+ {
+ for (size_t i = 0; i < nTicks; ++i) {
+ steadyClock->advance(tick);
+ systemClock->advance(tick);
+
+ if (g_ioService.stopped()) {
+ g_ioService.reset();
+ }
+
+ g_ioService.poll();
+ }
+ }
+
+protected:
+ shared_ptr<ndn::time::UnitTestSteadyClock> steadyClock;
+ shared_ptr<ndn::time::UnitTestSystemClock> systemClock;
+};
+
} // namespace test
} // namespace nlsr
diff --git a/tests/test-nlsr.cpp b/tests/test-nlsr.cpp
index ec53820..74a3f47 100644
--- a/tests/test-nlsr.cpp
+++ b/tests/test-nlsr.cpp
@@ -20,10 +20,13 @@
*
**/
- #include "test-common.hpp"
- #include "dummy-face.hpp"
+#include "test-common.hpp"
+#include "dummy-face.hpp"
- #include "nlsr.hpp"
+#include "nlsr.hpp"
+
+#include <ndn-cxx/management/nfd-face-event-notification.hpp>
+#include <ndn-cxx/util/dummy-client-face.hpp>
namespace nlsr {
namespace test {
@@ -106,6 +109,80 @@
BOOST_CHECK_EQUAL(rt.getRoutingCalcInterval(), ndn::time::seconds(9));
}
+BOOST_FIXTURE_TEST_CASE(FaceDestroyEvent, UnitTestTimeFixture)
+{
+ shared_ptr<ndn::util::DummyClientFace> face = ndn::util::makeDummyClientFace(g_ioService);
+ Nlsr nlsr(g_ioService, g_scheduler, ndn::ref(*face));
+
+ // Simulate loading configuration file
+ ConfParameter& conf = nlsr.getConfParameter();
+ conf.setNetwork("/ndn");
+ conf.setSiteName("/site");
+ conf.setRouterName("/%C1.router/this-router");
+ conf.setAdjLsaBuildInterval(0);
+ conf.setRoutingCalcInterval(0);
+
+ // Add active neighbors
+ AdjacencyList& neighbors = nlsr.getAdjacencyList();
+
+ uint64_t destroyFaceId = 128;
+
+ // Create a neighbor whose Face will be destroyed
+ Adjacent failNeighbor("/ndn/neighborA", "uri://faceA", 10, Adjacent::STATUS_ACTIVE, 0,
+ destroyFaceId);
+ neighbors.insert(failNeighbor);
+
+ // Create an additional neighbor so an adjacency LSA can be built after the face is destroyed
+ Adjacent otherNeighbor("/ndn/neighborB", "uri://faceB", 25, Adjacent::STATUS_ACTIVE, 0, 256);
+ neighbors.insert(otherNeighbor);
+
+ nlsr.initialize();
+
+ // Simulate successful HELLO responses
+ nlsr.getLsdb().scheduleAdjLsaBuild();
+
+ // Run the scheduler to build an adjacency LSA
+ this->advanceClocks(ndn::time::milliseconds(1));
+
+ // Make sure an adjacency LSA was built
+ ndn::Name key = ndn::Name(nlsr.getConfParameter().getRouterPrefix()).append(AdjLsa::TYPE_STRING);
+ AdjLsa* lsa = nlsr.getLsdb().findAdjLsa(key);
+ BOOST_REQUIRE(lsa != nullptr);
+
+ uint32_t lastAdjLsaSeqNo = nlsr.getSequencingManager().getAdjLsaSeq();
+
+ // Make sure the routing table was calculated
+ RoutingTableEntry* rtEntry = nlsr.getRoutingTable().findRoutingTableEntry(failNeighbor.getName());
+ BOOST_REQUIRE(rtEntry != nullptr);
+ BOOST_REQUIRE_EQUAL(rtEntry->getNexthopList().getSize(), 1);
+
+ // Receive FaceEventDestroyed notification
+ ndn::nfd::FaceEventNotification event;
+ event.setKind(ndn::nfd::FACE_EVENT_DESTROYED)
+ .setFaceId(destroyFaceId);
+
+ shared_ptr<ndn::Data> data = make_shared<ndn::Data>("/localhost/nfd/faces/events/%FE%00");
+ data->setContent(event.wireEncode());
+ nlsr.getKeyChain().sign(*data);
+
+ face->receive(*data);
+
+ // Run the scheduler to build an adjacency LSA
+ this->advanceClocks(ndn::time::milliseconds(1));
+
+ Adjacent updatedNeighbor = neighbors.getAdjacent(failNeighbor.getName());
+
+ BOOST_CHECK_EQUAL(updatedNeighbor.getFaceId(), 0);
+ BOOST_CHECK_EQUAL(updatedNeighbor.getInterestTimedOutNo(),
+ nlsr.getConfParameter().getInterestRetryNumber());
+ BOOST_CHECK_EQUAL(updatedNeighbor.getStatus(), Adjacent::STATUS_INACTIVE);
+ BOOST_CHECK_EQUAL(nlsr.getSequencingManager().getAdjLsaSeq(), lastAdjLsaSeqNo + 1);
+
+ // Make sure the routing table was recalculated
+ rtEntry = nlsr.getRoutingTable().findRoutingTableEntry(failNeighbor.getName());
+ BOOST_CHECK(rtEntry == nullptr);
+}
+
BOOST_AUTO_TEST_SUITE_END()
} //namespace test