NFD: Named Data Networking Forwarding Daemon 24.07-28-gdcc0e6e0
Loading...
Searching...
No Matches
readvertise.cpp
Go to the documentation of this file.
1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2014-2025, Regents of the University of California,
4 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
10 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24 */
25
26#include "readvertise.hpp"
27#include "common/global.hpp"
28#include "common/logger.hpp"
29
30#include <ndn-cxx/util/random.hpp>
31
32namespace nfd::rib {
33
34NFD_LOG_INIT(Readvertise);
35
36constexpr time::milliseconds RETRY_DELAY_MIN = 50_s;
37constexpr time::milliseconds RETRY_DELAY_MAX = 1_h;
38
39static time::milliseconds
40randomizeTimer(time::milliseconds baseTimer)
41{
42 std::uniform_int_distribution<> dist(-5, 5);
43 auto newTime = baseTimer + time::milliseconds(dist(ndn::random::getRandomNumberEngine()));
44 return std::max(newTime, 0_ms);
45}
46
48 unique_ptr<ReadvertisePolicy> policy,
49 unique_ptr<ReadvertiseDestination> destination)
50 : m_policy(std::move(policy))
51 , m_destination(std::move(destination))
52{
53 m_addRouteConn = rib.afterAddRoute.connect([this] (const auto& r) { this->afterAddRoute(r); });
54 m_removeRouteConn = rib.beforeRemoveRoute.connect([this] (const auto& r) { this->beforeRemoveRoute(r); });
55
56 m_destination->afterAvailabilityChange.connect([this] (bool isAvailable) {
57 if (isAvailable) {
58 this->afterDestinationAvailable();
59 }
60 else {
61 this->afterDestinationUnavailable();
62 }
63 });
64}
65
66void
67Readvertise::afterAddRoute(const RibRouteRef& ribRoute)
68{
69 std::optional<ReadvertiseAction> action = m_policy->handleNewRoute(ribRoute);
70 if (!action) {
71 NFD_LOG_DEBUG("add-route " << ribRoute.entry->getName() << " face=" << ribRoute.route->faceId <<
72 " origin=" << ribRoute.route->origin << " -> not-readvertising");
73 return;
74 }
75
76 auto [rrIt, isNewRr] = m_rrs.emplace(action->prefix, action->cost);
77 if (!isNewRr && rrIt->signer != action->signer) {
78 NFD_LOG_WARN("add-route " << ribRoute.entry->getName() << " face=" << ribRoute.route->faceId <<
79 " origin=" << ribRoute.route->origin << " -> readvertising-as " << action->prefix <<
80 " old-signer=" << rrIt->signer << " new-signer=" << action->signer);
81 }
82 rrIt->signer = action->signer;
83
84 bool isNewInMap = m_routeToRr.try_emplace(ribRoute, rrIt).second;
85 BOOST_VERIFY(isNewInMap);
86
87 if (rrIt->nRibRoutes++ > 0) {
88 NFD_LOG_DEBUG("add-route " << ribRoute.entry->getName() << " face=" << ribRoute.route->faceId <<
89 " origin=" << ribRoute.route->origin << " -> already-readvertised-as " << action->prefix);
90 return;
91 }
92
93 NFD_LOG_DEBUG("add-route " << ribRoute.entry->getName() << " face=" << ribRoute.route->faceId <<
94 " origin=" << ribRoute.route->origin << " -> readvertising-as " << action->prefix <<
95 " cost=" << action->cost << " signer=" << action->signer);
96 rrIt->retryDelay = RETRY_DELAY_MIN;
97 this->advertise(rrIt);
98}
99
100void
101Readvertise::beforeRemoveRoute(const RibRouteRef& ribRoute)
102{
103 auto indexIt = m_routeToRr.find(ribRoute);
104 if (indexIt == m_routeToRr.end()) {
105 NFD_LOG_DEBUG("remove-route " << ribRoute.entry->getName() << " face=" << ribRoute.route->faceId <<
106 " origin=" << ribRoute.route->origin << " -> not-readvertised");
107 return;
108 }
109
110 auto rrIt = indexIt->second;
111 m_routeToRr.erase(indexIt);
112
113 if (--rrIt->nRibRoutes > 0) {
114 NFD_LOG_DEBUG("remove-route " << ribRoute.entry->getName() << " face=" << ribRoute.route->faceId <<
115 " origin=" << ribRoute.route->origin << " -> needed-by " << rrIt->nRibRoutes);
116 return;
117 }
118
119 rrIt->retryDelay = RETRY_DELAY_MIN;
120 this->withdraw(rrIt);
121}
122
123void
124Readvertise::afterDestinationAvailable()
125{
126 for (auto rrIt = m_rrs.begin(); rrIt != m_rrs.end(); ++rrIt) {
127 rrIt->retryDelay = RETRY_DELAY_MIN;
128 this->advertise(rrIt);
129 }
130}
131
132void
133Readvertise::afterDestinationUnavailable()
134{
135 for (auto rrIt = m_rrs.begin(); rrIt != m_rrs.end();) {
136 if (rrIt->nRibRoutes > 0) {
137 rrIt->retryEvt.cancel(); // stop retrying or refreshing
138 ++rrIt;
139 }
140 else {
141 rrIt = m_rrs.erase(rrIt); // assume withdraw has completed
142 }
143 }
144}
145
146void
147Readvertise::advertise(ReadvertisedRouteContainer::iterator rrIt)
148{
149 BOOST_ASSERT(rrIt->nRibRoutes > 0);
150
151 if (!m_destination->isAvailable()) {
152 NFD_LOG_DEBUG("advertise " << rrIt->prefix << " -> destination unavailable");
153 return;
154 }
155
156 m_destination->advertise(*rrIt,
157 [=] {
158 NFD_LOG_DEBUG("advertise " << rrIt->prefix << " -> success");
159 rrIt->retryDelay = RETRY_DELAY_MIN;
160 rrIt->retryEvt = getScheduler().schedule(randomizeTimer(m_policy->getRefreshInterval()),
161 [=] { advertise(rrIt); });
162 },
163 [=] (const std::string& msg) {
164 NFD_LOG_DEBUG("advertise " << rrIt->prefix << " -> failure: " << msg);
165 rrIt->retryDelay = std::min(RETRY_DELAY_MAX, rrIt->retryDelay * 2);
166 rrIt->retryEvt = getScheduler().schedule(randomizeTimer(rrIt->retryDelay),
167 [=] { advertise(rrIt); });
168 });
169}
170
171void
172Readvertise::withdraw(ReadvertisedRouteContainer::iterator rrIt)
173{
174 BOOST_ASSERT(rrIt->nRibRoutes == 0);
175
176 if (!m_destination->isAvailable()) {
177 NFD_LOG_DEBUG("withdraw " << rrIt->prefix << " -> destination unavailable");
178 m_rrs.erase(rrIt);
179 return;
180 }
181
182 m_destination->withdraw(*rrIt,
183 [=] {
184 NFD_LOG_DEBUG("withdraw " << rrIt->prefix << " -> success");
185 m_rrs.erase(rrIt);
186 },
187 [=] (const std::string& msg) {
188 NFD_LOG_DEBUG("withdraw " << rrIt->prefix << " -> failure: " << msg);
189 rrIt->retryDelay = std::min(RETRY_DELAY_MAX, rrIt->retryDelay * 2);
190 rrIt->retryEvt = getScheduler().schedule(randomizeTimer(rrIt->retryDelay),
191 [=] { withdraw(rrIt); });
192 });
193}
194
195} // namespace nfd::rib
Readvertise(Rib &rib, unique_ptr< ReadvertisePolicy > policy, unique_ptr< ReadvertiseDestination > destination)
Represents the Routing Information Base.
Definition rib.hpp:70
signal::Signal< Rib, RibRouteRef > afterAddRoute
Signals after a Route is added.
Definition rib.hpp:235
signal::Signal< Rib, RibRouteRef > beforeRemoveRoute
Signals before a route is removed.
Definition rib.hpp:239
#define NFD_LOG_INIT(name)
Definition logger.hpp:31
#define NFD_LOG_WARN
Definition logger.hpp:40
#define NFD_LOG_DEBUG
Definition logger.hpp:38
constexpr time::milliseconds RETRY_DELAY_MAX
static time::milliseconds randomizeTimer(time::milliseconds baseTimer)
constexpr time::milliseconds RETRY_DELAY_MIN
ndn::Scheduler & getScheduler()
Returns the global Scheduler instance for the calling thread.
Definition global.cpp:45
References a route.
Definition rib.hpp:47
shared_ptr< RibEntry > entry
Definition rib.hpp:48
RibEntry::const_iterator route
Definition rib.hpp:49