Loading...
Searching...
No Matches
hello-protocol.cpp
Go to the documentation of this file.
1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2014-2024, The University of Memphis,
4 * Regents of the University of California
5 *
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/>.
19 */
20
21#include "hello-protocol.hpp"
22#include "nlsr.hpp"
23#include "lsdb.hpp"
24#include "logger.hpp"
26
27#include <ndn-cxx/encoding/nfd-constants.hpp>
28
29namespace nlsr {
30
31INIT_LOGGER(HelloProtocol);
32
33HelloProtocol::HelloProtocol(ndn::Face& face, ndn::KeyChain& keyChain,
34 ConfParameter& confParam, RoutingTable& routingTable,
35 Lsdb& lsdb)
36 : m_face(face)
37 , m_scheduler(m_face.getIoContext())
38 , m_keyChain(keyChain)
39 , m_signingInfo(confParam.getSigningInfo())
40 , m_confParam(confParam)
41 , m_routingTable(routingTable)
42 , m_lsdb(lsdb)
43 , m_adjacencyList(m_confParam.getAdjacencyList())
44{
45 ndn::Name name(m_confParam.getRouterPrefix());
46 name.append(NLSR_COMPONENT);
47 name.append(INFO_COMPONENT);
48
49 NLSR_LOG_DEBUG("Setting interest filter for Hello interest: " << name);
50
51 m_face.setInterestFilter(ndn::InterestFilter(name).allowLoopback(false),
52 [this] (const auto& name, const auto& interest) {
53 processInterest(name, interest);
54 },
55 [] (const auto& name) {
56 NLSR_LOG_DEBUG("Successfully registered prefix: " << name);
57 },
58 [] (const auto& name, const auto& resp) {
59 NLSR_LOG_ERROR("Failed to register prefix " << name);
60 NDN_THROW(std::runtime_error("Failed to register hello prefix: " + resp));
61 },
62 m_signingInfo, ndn::nfd::ROUTE_FLAG_CAPTURE);
63}
64
65void
66HelloProtocol::expressInterest(const ndn::Name& interestName, uint32_t seconds)
67{
68 NLSR_LOG_DEBUG("Expressing Interest: " << interestName);
69 ndn::Interest interest(interestName);
70 interest.setInterestLifetime(ndn::time::seconds(seconds));
71 interest.setMustBeFresh(true);
72 interest.setCanBePrefix(true);
73 m_face.expressInterest(interest,
74 std::bind(&HelloProtocol::onContent, this, _1, _2),
75 [this, seconds] (const auto& interest, const auto& nack) {
76 NDN_LOG_TRACE("Received Nack with reason: " << nack.getReason());
77 NDN_LOG_TRACE("Will treat as timeout in " << 2 * seconds << " seconds");
78 m_scheduler.schedule(ndn::time::seconds(2 * seconds),
79 [this, interest] { processInterestTimedOut(interest); });
80 },
81 std::bind(&HelloProtocol::processInterestTimedOut, this, _1));
82
83 // increment SENT_HELLO_INTEREST
85}
86
87void
88HelloProtocol::sendHelloInterest(const ndn::Name& neighbor)
89{
90 auto adjacent = m_adjacencyList.findAdjacent(neighbor);
91 if (adjacent == m_adjacencyList.end()) {
92 return;
93 }
94
95 // If this adjacency has a Face, just proceed as usual.
96 if(adjacent->getFaceId() != 0) {
97 // interest name: /<neighbor>/NLSR/INFO/<router>
98 ndn::Name interestName = adjacent->getName() ;
99 interestName.append(NLSR_COMPONENT);
100 interestName.append(INFO_COMPONENT);
101 interestName.append(ndn::tlv::GenericNameComponent, m_confParam.getRouterPrefix().wireEncode());
102 expressInterest(interestName, m_confParam.getInterestResendTime());
103 NLSR_LOG_DEBUG("Sending HELLO interest: " << interestName);
104 }
105
106 m_scheduler.schedule(ndn::time::seconds(m_confParam.getInfoInterestInterval()),
107 [this, neighbor] { sendHelloInterest(neighbor); });
108}
109
110void
111HelloProtocol::processInterest(const ndn::Name& name,
112 const ndn::Interest& interest)
113{
114 // interest name: /<neighbor>/NLSR/INFO/<router>
115 const ndn::Name interestName = interest.getName();
116
117 // increment RCV_HELLO_INTEREST
119
120 NLSR_LOG_DEBUG("Interest received for Name: " << interestName);
121 if (interestName.get(-2).toUri() != INFO_COMPONENT) {
122 NLSR_LOG_DEBUG("INFO_COMPONENT not found or Interest Name " << interestName
123 << " does not match expression");
124 return;
125 }
126
127 ndn::Name neighbor(interestName.get(-1).blockFromValue());
128 NLSR_LOG_DEBUG("Neighbor: " << neighbor);
129 if (m_adjacencyList.isNeighbor(neighbor)) {
130 auto data = std::make_shared<ndn::Data>();
131 data->setName(ndn::Name(interest.getName()).appendVersion());
132 // A Hello reply being cached longer than is needed to fufill an Interest
133 // can cause counterintuitive behavior. Consequently, we use the default
134 // minimum of 0 ms.
135 data->setFreshnessPeriod(0_ms);
136 data->setContent(ndn::make_span(reinterpret_cast<const uint8_t*>(INFO_COMPONENT.data()),
137 INFO_COMPONENT.size()));
138
139 m_keyChain.sign(*data, m_signingInfo);
140
141 NLSR_LOG_DEBUG("Sending out data for name: " << interest.getName());
142 m_face.put(*data);
143 // increment SENT_HELLO_DATA
145
146 auto adjacent = m_adjacencyList.findAdjacent(neighbor);
147 // If this neighbor was previously inactive, send our own hello interest, too
148 if (adjacent->getStatus() == Adjacent::STATUS_INACTIVE) {
149 // We can only do that if the neighbor currently has a face.
150 if (adjacent->getFaceId() != 0) {
151 // interest name: /<neighbor>/NLSR/INFO/<router>
152 ndn::Name interestName(neighbor);
153 interestName.append(NLSR_COMPONENT);
154 interestName.append(INFO_COMPONENT);
155 interestName.append(ndn::tlv::GenericNameComponent, m_confParam.getRouterPrefix().wireEncode());
156 expressInterest(interestName, m_confParam.getInterestResendTime());
157 }
158 }
159 }
160}
161
162void
163HelloProtocol::processInterestTimedOut(const ndn::Interest& interest)
164{
165 // interest name: /<neighbor>/NLSR/INFO/<router>
166 const ndn::Name interestName(interest.getName());
167 NLSR_LOG_DEBUG("Interest timed out for Name: " << interestName);
168 if (interestName.get(-2).toUri() != INFO_COMPONENT) {
169 return;
170 }
171 ndn::Name neighbor = interestName.getPrefix(-3);
172 NLSR_LOG_DEBUG("Neighbor: " << neighbor);
173 m_adjacencyList.incrementTimedOutInterestCount(neighbor);
174
175 Adjacent::Status status = m_adjacencyList.getStatusOfNeighbor(neighbor);
176
177 uint32_t infoIntTimedOutCount = m_adjacencyList.getTimedOutInterestCount(neighbor);
178 NLSR_LOG_DEBUG("Status: " << status);
179 NLSR_LOG_DEBUG("Info Interest Timed out: " << infoIntTimedOutCount);
180 if (infoIntTimedOutCount < m_confParam.getInterestRetryNumber()) {
181 // interest name: /<neighbor>/NLSR/INFO/<router>
182 ndn::Name interestName(neighbor);
183 interestName.append(NLSR_COMPONENT);
184 interestName.append(INFO_COMPONENT);
185 interestName.append(ndn::tlv::GenericNameComponent, m_confParam.getRouterPrefix().wireEncode());
186 NLSR_LOG_DEBUG("Resending interest: " << interestName);
187 expressInterest(interestName, m_confParam.getInterestResendTime());
188 }
189 else if (status == Adjacent::STATUS_ACTIVE) {
190 m_adjacencyList.setStatusOfNeighbor(neighbor, Adjacent::STATUS_INACTIVE);
191
192 NLSR_LOG_DEBUG("Neighbor: " << neighbor << " status changed to INACTIVE");
193
194 if (m_confParam.getHyperbolicState() == HYPERBOLIC_STATE_ON) {
195 m_routingTable.scheduleRoutingTableCalculation();
196 }
197 else {
198 m_lsdb.scheduleAdjLsaBuild();
199 }
200 }
201}
202
203// This is the first function that incoming Hello data will
204// see. This checks if the data appears to be signed, and passes it
205// on to validate the content of the data.
206void
207HelloProtocol::onContent(const ndn::Interest& interest, const ndn::Data& data)
208{
209 NLSR_LOG_DEBUG("Received data for INFO(name): " << data.getName());
210 auto kl = data.getKeyLocator();
211 if (kl && kl->getType() == ndn::tlv::Name) {
212 NLSR_LOG_DEBUG("Data signed with: " << kl->getName());
213 }
214 m_confParam.getValidator().validate(data,
215 std::bind(&HelloProtocol::onContentValidated, this, _1),
216 std::bind(&HelloProtocol::onContentValidationFailed,
217 this, _1, _2));
218}
219
220void
221HelloProtocol::onContentValidated(const ndn::Data& data)
222{
223 // data name: /<neighbor>/NLSR/INFO/<router>/<version>
224 ndn::Name dataName = data.getName();
225 NLSR_LOG_DEBUG("Data validation successful for INFO(name): " << dataName);
226
227 if (dataName.get(-3).toUri() == INFO_COMPONENT) {
228 ndn::Name neighbor = dataName.getPrefix(-4);
229
230 Adjacent::Status oldStatus = m_adjacencyList.getStatusOfNeighbor(neighbor);
231 m_adjacencyList.setStatusOfNeighbor(neighbor, Adjacent::STATUS_ACTIVE);
232 m_adjacencyList.setTimedOutInterestCount(neighbor, 0);
233 Adjacent::Status newStatus = m_adjacencyList.getStatusOfNeighbor(neighbor);
234
235 NLSR_LOG_DEBUG("Neighbor: " << neighbor);
236 NLSR_LOG_DEBUG("Old Status: " << oldStatus << ", New Status: " << newStatus);
237 // change in Adjacency list
238 if ((oldStatus - newStatus) != 0) {
239 if (m_confParam.getHyperbolicState() == HYPERBOLIC_STATE_ON) {
240 m_routingTable.scheduleRoutingTableCalculation();
241 }
242 else {
243 m_lsdb.scheduleAdjLsaBuild();
244 }
246 }
247 }
248 // increment RCV_HELLO_DATA
250}
251
252void
253HelloProtocol::onContentValidationFailed(const ndn::Data& data,
254 const ndn::security::ValidationError& ve)
255{
256 NLSR_LOG_DEBUG("Validation error: " << ve);
257}
258
259} // namespace nlsr
int32_t getTimedOutInterestCount(const ndn::Name &neighbor) const
void incrementTimedOutInterestCount(const ndn::Name &neighbor)
void setTimedOutInterestCount(const ndn::Name &neighbor, uint32_t count)
const_iterator end() const
Adjacent::Status getStatusOfNeighbor(const ndn::Name &neighbor) const
bool isNeighbor(const ndn::Name &adjName) const
void setStatusOfNeighbor(const ndn::Name &neighbor, Adjacent::Status status)
AdjacencyList::iterator findAdjacent(const ndn::Name &adjName)
A class to house all the configuration parameters for NLSR.
uint32_t getInfoInterestInterval() const
const ndn::Name & getRouterPrefix() const
uint32_t getInterestRetryNumber() const
uint32_t getInterestResendTime() const
HyperbolicState getHyperbolicState() const
ndn::security::ValidatorConfig & getValidator()
HelloProtocol(ndn::Face &face, ndn::KeyChain &keyChain, ConfParameter &confParam, RoutingTable &routingTable, Lsdb &lsdb)
void sendHelloInterest(const ndn::Name &neighbor)
Sends Hello Interests to all neighbors.
ndn::signal::Signal< HelloProtocol, Statistics::PacketType > hpIncrementSignal
static const std::string INFO_COMPONENT
static const std::string NLSR_COMPONENT
void processInterest(const ndn::Name &name, const ndn::Interest &interest)
Processes a Hello Interest from a neighbor.
void expressInterest(const ndn::Name &interestNamePrefix, uint32_t seconds)
Sends a Hello Interest packet.
ndn::signal::Signal< HelloProtocol, const ndn::Name & > onInitialHelloDataValidated
void scheduleAdjLsaBuild()
Schedules a build of this router's LSA.
Definition lsdb.cpp:122
void scheduleRoutingTableCalculation()
Schedules a calculation event in the event scheduler only if one isn't already scheduled.
Copyright (c) 2014-2018, The University of Memphis, Regents of the University of California.
#define NLSR_LOG_DEBUG(x)
Definition logger.hpp:38
#define INIT_LOGGER(name)
Definition logger.hpp:35
#define NLSR_LOG_ERROR(x)
Definition logger.hpp:41
Copyright (c) 2014-2020, The University of Memphis, Regents of the University of California.
@ HYPERBOLIC_STATE_ON