blob: bdb1d32f92829f86f312e4efb27aa8e78f34ab41 [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, The University of Memphis,
* Regents of the University of California,
* Arizona Board of Regents.
*
* This file is part of NLSR (Named-data Link State Routing).
* See AUTHORS.md for complete list of NLSR authors and contributors.
*
* NLSR is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* NLSR, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
**/
#ifndef NLSR_LSDB_HPP
#define NLSR_LSDB_HPP
#include "conf-parameter.hpp"
#include "lsa/lsa.hpp"
#include "lsa/name-lsa.hpp"
#include "lsa/coordinate-lsa.hpp"
#include "lsa/adj-lsa.hpp"
#include "sequencing-manager.hpp"
#include "test-access-control.hpp"
#include "communication/sync-logic-handler.hpp"
#include "statistics.hpp"
#include "route/name-prefix-table.hpp"
#include <ndn-cxx/security/key-chain.hpp>
#include <ndn-cxx/util/signal.hpp>
#include <ndn-cxx/util/time.hpp>
#include <ndn-cxx/util/segment-fetcher.hpp>
#include <ndn-cxx/ims/in-memory-storage-persistent.hpp>
#include <PSync/segment-publisher.hpp>
#include <utility>
#include <boost/cstdint.hpp>
namespace nlsr {
class Lsdb
{
public:
Lsdb(ndn::Face& face, ndn::KeyChain& keyChain, ConfParameter& confParam,
NamePrefixTable& namePrefixTable, RoutingTable& routingTable);
~Lsdb();
bool
isLsaNew(const ndn::Name& routerName, const Lsa::Type& lsaType, const uint64_t& sequenceNumber);
bool
doesLsaExist(const ndn::Name& key, const Lsa::Type& lsType);
/*! \brief Builds a name LSA for this router and then installs it
into the LSDB.
*/
bool
buildAndInstallOwnNameLsa();
/*! \brief Returns the name LSA with the given key.
\param key The name of the router that the desired LSA comes from.
*/
NameLsa*
findNameLsa(const ndn::Name& key);
/*! \brief Installs a name LSA into the LSDB
\param nlsa The name LSA to install into the LSDB.
*/
bool
installNameLsa(NameLsa& nlsa);
/*! \brief Remove a name LSA from the LSDB.
\param key The name of the router that published the LSA to remove.
This function will remove a name LSA from the LSDB by finding an
LSA whose name matches key. This removal also causes the NPT to
remove those name prefixes if no more LSAs advertise them.
*/
bool
removeNameLsa(const ndn::Name& key);
/*! Returns whether a seq. no. from a certain router signals a new LSA.
\param key The name of the originating router.
\param seqNo The sequence number to check.
*/
bool
isNameLsaNew(const ndn::Name& key, uint64_t seqNo);
void
writeNameLsdbLog();
const std::list<NameLsa>&
getNameLsdb() const;
/*! \brief Builds a cor. LSA for this router and installs it into the LSDB. */
bool
buildAndInstallOwnCoordinateLsa();
/*! \brief Finds a cor. LSA in the LSDB.
\param key The name of the originating router that published the LSA.
*/
CoordinateLsa*
findCoordinateLsa(const ndn::Name& key);
/*! \brief Installs a cor. LSA into the LSDB.
\param clsa The cor. LSA to install.
*/
bool
installCoordinateLsa(CoordinateLsa& clsa);
/*! \brief Removes a cor. LSA from the LSDB.
\param key The name of the router that published the LSA to remove.
Removes the coordinate LSA whose origin router name matches that
given by key. Additionally, ask the NPT to remove the prefix,
which will occur if no other LSAs point there.
*/
bool
removeCoordinateLsa(const ndn::Name& key);
/*! \brief Returns whether a cor. LSA from a router is new or not.
\param key The name prefix of the originating router.
\param seqNo The sequence number of the candidate LSA.
*/
bool
isCoordinateLsaNew(const ndn::Name& key, uint64_t seqNo);
void
writeCorLsdbLog();
const std::list<CoordinateLsa>&
getCoordinateLsdb() const;
//function related to Adj LSDB
/*! \brief Schedules a build of this router's LSA. */
void
scheduleAdjLsaBuild();
/*! \brief Wrapper event to build and install an adj. LSA for this router. */
bool
buildAndInstallOwnAdjLsa();
/*! \brief Removes an adj. LSA from the LSDB.
\param key The name of the publishing router whose LSA to remove.
*/
bool
removeAdjLsa(const ndn::Name& key);
/*! \brief Returns whether an LSA is new.
\param key The name of the publishing router.
\param seqNo The seq. no. of the candidate LSA.
This function determines whether the LSA with the name key and
seq. no. seqNo would be new to this LSDB.
*/
bool
isAdjLsaNew(const ndn::Name& key, uint64_t seqNo);
/*! \brief Installs an adj. LSA into the LSDB.
\param alsa The adj. LSA to add to the LSDB.
*/
bool
installAdjLsa(AdjLsa& alsa);
/*! \brief Finds an adj. LSA in the LSDB.
\param key The name of the publishing router whose LSA to find.
*/
AdjLsa*
findAdjLsa(const ndn::Name& key);
const std::list<AdjLsa>&
getAdjLsdb() const;
void
setAdjLsaBuildInterval(uint32_t interval)
{
m_adjLsaBuildInterval = ndn::time::seconds(interval);
}
void
writeAdjLsdbLog();
void
expressInterest(const ndn::Name& interestName, uint32_t timeoutCount,
ndn::time::steady_clock::TimePoint deadline = DEFAULT_LSA_RETRIEVAL_DEADLINE);
/* \brief Process interest which can be either:
* 1) Discovery interest from segment fetcher:
* /localhop/<network>/nlsr/LSA/<site>/<router>/<lsaType>/<seqNo>
* 2) Interest containing segment number:
* /localhop/<network>/nlsr/LSA/<site>/<router>/<lsaType>/<seqNo>/<version>/<segmentNo>
*/
void
processInterest(const ndn::Name& name, const ndn::Interest& interest);
bool
getIsBuildAdjLsaSheduled()
{
return m_isBuildAdjLsaSheduled;
}
SyncLogicHandler&
getSync() {
return m_sync;
}
private:
/* \brief Add a name LSA to the LSDB if it isn't already there.
\param nlsa The candidade name LSA.
*/
bool
addNameLsa(NameLsa& nlsa);
/*! \brief Returns whether the LSDB contains some LSA.
\param key The name of the publishing router whose LSA to check for.
*/
bool
doesNameLsaExist(const ndn::Name& key);
/*! \brief Adds a cor. LSA to the LSDB if it isn't already there.
\param clsa The candidate cor. LSA.
*/
bool
addCoordinateLsa(CoordinateLsa& clsa);
/*! \brief Returns whether a cor. LSA is in the LSDB.
\param key The name of the router that published the queried LSA.
*/
bool
doesCoordinateLsaExist(const ndn::Name& key);
/*! \brief Attempts to construct an adj. LSA.
This function will attempt to construct an adjacency LSA. An LSA
can only be built when the status of all of the router's neighbors
is known. That is, when we are not currently trying to contact any
neighbor.
*/
void
buildAdjLsa();
/*! \brief Adds an adj. LSA to the LSDB if it isn't already there.
\param alsa The candidate adj. LSA to add to the LSDB.
*/
bool
addAdjLsa(AdjLsa& alsa);
/*! \brief Returns whether the LSDB contains an LSA.
\param key The name of a router whose LSA to check for in the LSDB.
*/
bool
doesAdjLsaExist(const ndn::Name& key);
/*! \brief Schedules a refresh/expire event in the scheduler.
\param key The name of the router that published the LSA.
\param seqNo The seq. no. associated with the LSA.
\param expTime How many seconds to wait before triggering the event.
*/
ndn::scheduler::EventId
scheduleNameLsaExpiration(const ndn::Name& key, int seqNo,
const ndn::time::seconds& expTime);
/*! \brief Either allow to expire, or refresh a name LSA.
\param lsaKey The name of the router that published the LSA.
\param seqNo The seq. no. of the LSA to check.
*/
void
expireOrRefreshNameLsa(const ndn::Name& lsaKey, uint64_t seqNo);
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
/*! \brief Schedules an expire/refresh event in the LSA.
\param key The name of the router whose LSA is in question.
\param seqNo The sequence number of the LSA to check.
\param expTime The number of seconds to wait before triggering the event.
*/
ndn::scheduler::EventId
scheduleAdjLsaExpiration(const ndn::Name& key, int seqNo,
const ndn::time::seconds& expTime);
private:
void
expireOrRefreshAdjLsa(const ndn::Name& lsaKey, uint64_t seqNo);
ndn::scheduler::EventId
scheduleCoordinateLsaExpiration(const ndn::Name& key, int seqNo,
const ndn::time::seconds& expTime);
void
expireOrRefreshCoordinateLsa(const ndn::Name& lsaKey,
uint64_t seqNo);
void
processInterestForNameLsa(const ndn::Interest& interest,
const ndn::Name& lsaKey,
uint64_t seqNo);
void
processInterestForAdjacencyLsa(const ndn::Interest& interest,
const ndn::Name& lsaKey,
uint64_t seqNo);
void
processInterestForCoordinateLsa(const ndn::Interest& interest,
const ndn::Name& lsaKey,
uint64_t seqNo);
void
processContentNameLsa(const ndn::Name& lsaKey,
uint64_t lsSeqNo, const ndn::Block& block);
void
processContentAdjacencyLsa(const ndn::Name& lsaKey,
uint64_t lsSeqNo, const ndn::Block& block);
void
processContentCoordinateLsa(const ndn::Name& lsaKey,
uint64_t lsSeqNo, const ndn::Block& block);
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
/*!
\brief Error callback when SegmentFetcher fails to return an LSA
In all error cases, a reattempt to fetch the LSA will be made.
Segment validation can fail either because the packet does not have a
valid signature (fatal) or because some of the certificates in the trust chain
could not be fetched (non-fatal).
Currently, the library does not provide clear indication (besides a plain-text message
in the error callback) of the reason for the failure nor the segment that failed
to be validated, thus we will continue to try to fetch the LSA until the deadline
is reached.
*/
void
onFetchLsaError(uint32_t errorCode,
const std::string& msg,
const ndn::Name& interestName,
uint32_t retransmitNo,
const ndn::time::steady_clock::TimePoint& deadline,
ndn::Name lsaName,
uint64_t seqNo);
/*!
\brief Success callback when SegmentFetcher returns a valid LSA
\param interestName The base Interest used to fetch the LSA in the format:
/<network>/NLSR/LSA/<site>/%C1.Router/<router>/<lsa-type>/<seqNo>
*/
void
afterFetchLsa(const ndn::ConstBufferPtr& bufferPtr, const ndn::Name& interestName);
void
emitSegmentValidatedSignal(const ndn::Data& data)
{
afterSegmentValidatedSignal(data);
}
private:
ndn::time::system_clock::TimePoint
getLsaExpirationTimePoint();
public:
static const ndn::Name::Component NAME_COMPONENT;
ndn::util::signal::Signal<Lsdb, Statistics::PacketType> lsaIncrementSignal;
ndn::util::signal::Signal<Lsdb, const ndn::Data&> afterSegmentValidatedSignal;
private:
ndn::Face& m_face;
ndn::Scheduler m_scheduler;
ConfParameter& m_confParam;
NamePrefixTable& m_namePrefixTable;
RoutingTable& m_routingTable;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
SyncLogicHandler m_sync;
private:
std::list<NameLsa> m_nameLsdb;
std::list<AdjLsa> m_adjLsdb;
std::list<CoordinateLsa> m_corLsdb;
ndn::time::seconds m_lsaRefreshTime;
std::string m_thisRouterPrefix;
typedef std::map<ndn::Name, uint64_t> SequenceNumberMap;
// Maps the name of an LSA to its highest known sequence number from sync;
// Used to stop NLSR from trying to fetch outdated LSAs
SequenceNumberMap m_highestSeqNo;
static const ndn::time::seconds GRACE_PERIOD;
static const ndn::time::steady_clock::TimePoint DEFAULT_LSA_RETRIEVAL_DEADLINE;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
ndn::time::seconds m_adjLsaBuildInterval;
SequencingManager m_sequencingManager;
private:
ndn::util::signal::ScopedConnection m_onNewLsaConnection;
std::set<std::shared_ptr<ndn::util::SegmentFetcher>> m_fetchers;
psync::SegmentPublisher m_segmentPublisher;
bool m_isBuildAdjLsaSheduled;
int64_t m_adjBuildCount;
ndn::scheduler::ScopedEventId m_scheduledAdjLsaBuild;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
ndn::InMemoryStoragePersistent m_lsaStorage;
};
} // namespace nlsr
#endif // NLSR_LSDB_HPP