blob: d5bedf8c839bc687278f05773046e4db759fbb45 [file] [log] [blame]
Junxiao Shi89c0ea02017-03-06 19:52:05 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento87fc0f82018-04-11 23:43:51 -04002/*
Junxiao Shifeddc3c2019-01-17 19:06:00 +00003 * Copyright (c) 2014-2019, Regents of the University of California,
Junxiao Shi89c0ea02017-03-06 19:52:05 +00004 * 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 "core/logger.hpp"
Davide Pesavento0a71dd32019-03-17 20:36:18 -040028#include "daemon/global.hpp"
Davide Pesaventob8bd5ee2019-02-03 22:53:40 -050029
30#include <ndn-cxx/util/random.hpp>
Junxiao Shi89c0ea02017-03-06 19:52:05 +000031
32namespace nfd {
33namespace rib {
34
Davide Pesaventoa3148082018-04-12 18:21:54 -040035NFD_LOG_INIT(Readvertise);
Junxiao Shi89c0ea02017-03-06 19:52:05 +000036
Davide Pesaventoe4b22382018-06-10 14:37:24 -040037const time::milliseconds Readvertise::RETRY_DELAY_MIN = 50_s;
38const time::milliseconds Readvertise::RETRY_DELAY_MAX = 3600_s;
Junxiao Shi89c0ea02017-03-06 19:52:05 +000039
40static time::milliseconds
41randomizeTimer(time::milliseconds baseTimer)
42{
Davide Pesaventob8bd5ee2019-02-03 22:53:40 -050043 std::uniform_int_distribution<> dist(-5, 5);
44 auto newTime = baseTimer + time::milliseconds(dist(ndn::random::getRandomNumberEngine()));
Davide Pesaventoe4b22382018-06-10 14:37:24 -040045 return std::max(newTime, 0_ms);
Junxiao Shi89c0ea02017-03-06 19:52:05 +000046}
47
Davide Pesavento0a71dd32019-03-17 20:36:18 -040048Readvertise::Readvertise(Rib& rib,
Davide Pesaventoe1bdc082018-10-11 21:20:23 -040049 unique_ptr<ReadvertisePolicy> policy,
Junxiao Shi89c0ea02017-03-06 19:52:05 +000050 unique_ptr<ReadvertiseDestination> destination)
Davide Pesavento0a71dd32019-03-17 20:36:18 -040051 : m_policy(std::move(policy))
Junxiao Shi89c0ea02017-03-06 19:52:05 +000052 , m_destination(std::move(destination))
53{
Davide Pesaventoe4b22382018-06-10 14:37:24 -040054 m_addRouteConn = rib.afterAddRoute.connect([this] (const auto& r) { this->afterAddRoute(r); });
55 m_removeRouteConn = rib.beforeRemoveRoute.connect([this] (const auto& r) { this->beforeRemoveRoute(r); });
Junxiao Shi89c0ea02017-03-06 19:52:05 +000056
57 m_destination->afterAvailabilityChange.connect([this] (bool isAvailable) {
58 if (isAvailable) {
59 this->afterDestinationAvailable();
60 }
61 else {
62 this->afterDestinationUnavailable();
63 }
64 });
65}
66
67void
68Readvertise::afterAddRoute(const RibRouteRef& ribRoute)
69{
Davide Pesavento87fc0f82018-04-11 23:43:51 -040070 optional<ReadvertiseAction> action = m_policy->handleNewRoute(ribRoute);
Junxiao Shi89c0ea02017-03-06 19:52:05 +000071 if (!action) {
72 NFD_LOG_DEBUG("add-route " << ribRoute.entry->getName() << '(' << ribRoute.route->faceId <<
73 ',' << ribRoute.route->origin << ") not-readvertising");
74 return;
75 }
76
77 ReadvertisedRouteContainer::iterator rrIt;
78 bool isNew = false;
Junxiao Shifeddc3c2019-01-17 19:06:00 +000079 std::tie(rrIt, isNew) = m_rrs.emplace(action->prefix);
Junxiao Shi89c0ea02017-03-06 19:52:05 +000080
81 if (!isNew && rrIt->signer != action->signer) {
82 NFD_LOG_WARN("add-route " << ribRoute.entry->getName() << '(' << ribRoute.route->faceId <<
83 ',' << ribRoute.route->origin << ") readvertising-as " << action->prefix <<
84 " old-signer " << rrIt->signer << " new-signer " << action->signer);
85 }
86 rrIt->signer = action->signer;
87
88 RouteRrIndex::iterator indexIt;
89 std::tie(indexIt, isNew) = m_routeToRr.emplace(ribRoute, rrIt);
90 BOOST_ASSERT(isNew);
91
92 if (rrIt->nRibRoutes++ > 0) {
93 NFD_LOG_DEBUG("add-route " << ribRoute.entry->getName() << '(' << ribRoute.route->faceId <<
94 ',' << ribRoute.route->origin << ") already-readvertised-as " << action->prefix);
95 return;
96 }
97
98 NFD_LOG_DEBUG("add-route " << ribRoute.entry->getName() << '(' << ribRoute.route->faceId <<
99 ',' << ribRoute.route->origin << ") readvertising-as " << action->prefix <<
100 " signer " << action->signer);
101 rrIt->retryDelay = RETRY_DELAY_MIN;
102 this->advertise(rrIt);
103}
104
105void
106Readvertise::beforeRemoveRoute(const RibRouteRef& ribRoute)
107{
108 auto indexIt = m_routeToRr.find(ribRoute);
109 if (indexIt == m_routeToRr.end()) {
110 NFD_LOG_DEBUG("remove-route " << ribRoute.entry->getName() << '(' << ribRoute.route->faceId <<
111 ',' << ribRoute.route->origin << ") not-readvertised");
112 return;
113 }
114
115 auto rrIt = indexIt->second;
116 m_routeToRr.erase(indexIt);
117
118 if (--rrIt->nRibRoutes > 0) {
119 NFD_LOG_DEBUG("remove-route " << ribRoute.entry->getName() << '(' << ribRoute.route->faceId <<
120 ',' << ribRoute.route->origin << ") needed-by " << rrIt->nRibRoutes);
121 return;
122 }
123
124 rrIt->retryDelay = RETRY_DELAY_MIN;
125 this->withdraw(rrIt);
126}
127
128void
129Readvertise::afterDestinationAvailable()
130{
131 for (auto rrIt = m_rrs.begin(); rrIt != m_rrs.end(); ++rrIt) {
132 rrIt->retryDelay = RETRY_DELAY_MIN;
133 this->advertise(rrIt);
134 }
135}
136
137void
138Readvertise::afterDestinationUnavailable()
139{
140 for (auto rrIt = m_rrs.begin(); rrIt != m_rrs.end();) {
141 if (rrIt->nRibRoutes > 0) {
142 rrIt->retryEvt.cancel(); // stop retrying or refreshing
143 ++rrIt;
144 }
145 else {
146 rrIt = m_rrs.erase(rrIt); // assume withdraw has completed
147 }
148 }
149}
150
151void
152Readvertise::advertise(ReadvertisedRouteContainer::iterator rrIt)
153{
154 BOOST_ASSERT(rrIt->nRibRoutes > 0);
155
156 if (!m_destination->isAvailable()) {
157 NFD_LOG_DEBUG("advertise " << rrIt->prefix << " destination-unavailable");
158 return;
159 }
160
161 m_destination->advertise(*rrIt,
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400162 [=] {
Junxiao Shi89c0ea02017-03-06 19:52:05 +0000163 NFD_LOG_DEBUG("advertise " << rrIt->prefix << " success");
164 rrIt->retryDelay = RETRY_DELAY_MIN;
Davide Pesavento0a71dd32019-03-17 20:36:18 -0400165 rrIt->retryEvt = getScheduler().schedule(randomizeTimer(m_policy->getRefreshInterval()),
166 [=] { advertise(rrIt); });
Junxiao Shi89c0ea02017-03-06 19:52:05 +0000167 },
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400168 [=] (const std::string& msg) {
Junxiao Shi89c0ea02017-03-06 19:52:05 +0000169 NFD_LOG_DEBUG("advertise " << rrIt->prefix << " failure " << msg);
170 rrIt->retryDelay = std::min(RETRY_DELAY_MAX, rrIt->retryDelay * 2);
Davide Pesavento0a71dd32019-03-17 20:36:18 -0400171 rrIt->retryEvt = getScheduler().schedule(randomizeTimer(rrIt->retryDelay),
172 [=] { advertise(rrIt); });
Junxiao Shi89c0ea02017-03-06 19:52:05 +0000173 });
174}
175
176void
177Readvertise::withdraw(ReadvertisedRouteContainer::iterator rrIt)
178{
179 BOOST_ASSERT(rrIt->nRibRoutes == 0);
180
181 if (!m_destination->isAvailable()) {
182 NFD_LOG_DEBUG("withdraw " << rrIt->prefix << " destination-unavailable");
183 m_rrs.erase(rrIt);
184 return;
185 }
186
187 m_destination->withdraw(*rrIt,
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400188 [=] {
Junxiao Shi89c0ea02017-03-06 19:52:05 +0000189 NFD_LOG_DEBUG("withdraw " << rrIt->prefix << " success");
190 m_rrs.erase(rrIt);
191 },
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400192 [=] (const std::string& msg) {
Junxiao Shi89c0ea02017-03-06 19:52:05 +0000193 NFD_LOG_DEBUG("withdraw " << rrIt->prefix << " failure " << msg);
194 rrIt->retryDelay = std::min(RETRY_DELAY_MAX, rrIt->retryDelay * 2);
Davide Pesavento0a71dd32019-03-17 20:36:18 -0400195 rrIt->retryEvt = getScheduler().schedule(randomizeTimer(rrIt->retryDelay),
196 [=] { withdraw(rrIt); });
Junxiao Shi89c0ea02017-03-06 19:52:05 +0000197 });
198}
199
200} // namespace rib
201} // namespace nfd