blob: 4c51a034561afddbf87cc65985b67e2a07eb08af [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"
28#include "core/random.hpp"
29
30namespace nfd {
31namespace rib {
32
Davide Pesaventoa3148082018-04-12 18:21:54 -040033NFD_LOG_INIT(Readvertise);
Junxiao Shi89c0ea02017-03-06 19:52:05 +000034
Davide Pesaventoe4b22382018-06-10 14:37:24 -040035const time::milliseconds Readvertise::RETRY_DELAY_MIN = 50_s;
36const time::milliseconds Readvertise::RETRY_DELAY_MAX = 3600_s;
Junxiao Shi89c0ea02017-03-06 19:52:05 +000037
38static time::milliseconds
39randomizeTimer(time::milliseconds baseTimer)
40{
41 std::uniform_int_distribution<uint64_t> dist(-5, 5);
42 time::milliseconds newTime = baseTimer + time::milliseconds(dist(getGlobalRng()));
Davide Pesaventoe4b22382018-06-10 14:37:24 -040043 return std::max(newTime, 0_ms);
Junxiao Shi89c0ea02017-03-06 19:52:05 +000044}
45
Davide Pesaventoe1bdc082018-10-11 21:20:23 -040046Readvertise::Readvertise(Rib& rib, ndn::util::Scheduler& scheduler,
47 unique_ptr<ReadvertisePolicy> policy,
Junxiao Shi89c0ea02017-03-06 19:52:05 +000048 unique_ptr<ReadvertiseDestination> destination)
Davide Pesaventoe1bdc082018-10-11 21:20:23 -040049 : m_scheduler(scheduler)
50 , m_policy(std::move(policy))
Junxiao Shi89c0ea02017-03-06 19:52:05 +000051 , m_destination(std::move(destination))
52{
Davide Pesaventoe4b22382018-06-10 14:37:24 -040053 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); });
Junxiao Shi89c0ea02017-03-06 19:52:05 +000055
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{
Davide Pesavento87fc0f82018-04-11 23:43:51 -040069 optional<ReadvertiseAction> action = m_policy->handleNewRoute(ribRoute);
Junxiao Shi89c0ea02017-03-06 19:52:05 +000070 if (!action) {
71 NFD_LOG_DEBUG("add-route " << ribRoute.entry->getName() << '(' << ribRoute.route->faceId <<
72 ',' << ribRoute.route->origin << ") not-readvertising");
73 return;
74 }
75
76 ReadvertisedRouteContainer::iterator rrIt;
77 bool isNew = false;
Junxiao Shifeddc3c2019-01-17 19:06:00 +000078 std::tie(rrIt, isNew) = m_rrs.emplace(action->prefix);
Junxiao Shi89c0ea02017-03-06 19:52:05 +000079
80 if (!isNew && rrIt->signer != action->signer) {
81 NFD_LOG_WARN("add-route " << ribRoute.entry->getName() << '(' << ribRoute.route->faceId <<
82 ',' << ribRoute.route->origin << ") readvertising-as " << action->prefix <<
83 " old-signer " << rrIt->signer << " new-signer " << action->signer);
84 }
85 rrIt->signer = action->signer;
86
87 RouteRrIndex::iterator indexIt;
88 std::tie(indexIt, isNew) = m_routeToRr.emplace(ribRoute, rrIt);
89 BOOST_ASSERT(isNew);
90
91 if (rrIt->nRibRoutes++ > 0) {
92 NFD_LOG_DEBUG("add-route " << ribRoute.entry->getName() << '(' << ribRoute.route->faceId <<
93 ',' << ribRoute.route->origin << ") already-readvertised-as " << action->prefix);
94 return;
95 }
96
97 NFD_LOG_DEBUG("add-route " << ribRoute.entry->getName() << '(' << ribRoute.route->faceId <<
98 ',' << ribRoute.route->origin << ") readvertising-as " << action->prefix <<
99 " signer " << action->signer);
100 rrIt->retryDelay = RETRY_DELAY_MIN;
101 this->advertise(rrIt);
102}
103
104void
105Readvertise::beforeRemoveRoute(const RibRouteRef& ribRoute)
106{
107 auto indexIt = m_routeToRr.find(ribRoute);
108 if (indexIt == m_routeToRr.end()) {
109 NFD_LOG_DEBUG("remove-route " << ribRoute.entry->getName() << '(' << ribRoute.route->faceId <<
110 ',' << ribRoute.route->origin << ") not-readvertised");
111 return;
112 }
113
114 auto rrIt = indexIt->second;
115 m_routeToRr.erase(indexIt);
116
117 if (--rrIt->nRibRoutes > 0) {
118 NFD_LOG_DEBUG("remove-route " << ribRoute.entry->getName() << '(' << ribRoute.route->faceId <<
119 ',' << ribRoute.route->origin << ") needed-by " << rrIt->nRibRoutes);
120 return;
121 }
122
123 rrIt->retryDelay = RETRY_DELAY_MIN;
124 this->withdraw(rrIt);
125}
126
127void
128Readvertise::afterDestinationAvailable()
129{
130 for (auto rrIt = m_rrs.begin(); rrIt != m_rrs.end(); ++rrIt) {
131 rrIt->retryDelay = RETRY_DELAY_MIN;
132 this->advertise(rrIt);
133 }
134}
135
136void
137Readvertise::afterDestinationUnavailable()
138{
139 for (auto rrIt = m_rrs.begin(); rrIt != m_rrs.end();) {
140 if (rrIt->nRibRoutes > 0) {
141 rrIt->retryEvt.cancel(); // stop retrying or refreshing
142 ++rrIt;
143 }
144 else {
145 rrIt = m_rrs.erase(rrIt); // assume withdraw has completed
146 }
147 }
148}
149
150void
151Readvertise::advertise(ReadvertisedRouteContainer::iterator rrIt)
152{
153 BOOST_ASSERT(rrIt->nRibRoutes > 0);
154
155 if (!m_destination->isAvailable()) {
156 NFD_LOG_DEBUG("advertise " << rrIt->prefix << " destination-unavailable");
157 return;
158 }
159
160 m_destination->advertise(*rrIt,
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400161 [=] {
Junxiao Shi89c0ea02017-03-06 19:52:05 +0000162 NFD_LOG_DEBUG("advertise " << rrIt->prefix << " success");
163 rrIt->retryDelay = RETRY_DELAY_MIN;
Davide Pesaventoe1bdc082018-10-11 21:20:23 -0400164 rrIt->retryEvt = m_scheduler.scheduleEvent(randomizeTimer(m_policy->getRefreshInterval()),
165 [=] { advertise(rrIt); });
Junxiao Shi89c0ea02017-03-06 19:52:05 +0000166 },
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400167 [=] (const std::string& msg) {
Junxiao Shi89c0ea02017-03-06 19:52:05 +0000168 NFD_LOG_DEBUG("advertise " << rrIt->prefix << " failure " << msg);
169 rrIt->retryDelay = std::min(RETRY_DELAY_MAX, rrIt->retryDelay * 2);
Davide Pesaventoe1bdc082018-10-11 21:20:23 -0400170 rrIt->retryEvt = m_scheduler.scheduleEvent(randomizeTimer(rrIt->retryDelay),
171 [=] { advertise(rrIt); });
Junxiao Shi89c0ea02017-03-06 19:52:05 +0000172 });
173}
174
175void
176Readvertise::withdraw(ReadvertisedRouteContainer::iterator rrIt)
177{
178 BOOST_ASSERT(rrIt->nRibRoutes == 0);
179
180 if (!m_destination->isAvailable()) {
181 NFD_LOG_DEBUG("withdraw " << rrIt->prefix << " destination-unavailable");
182 m_rrs.erase(rrIt);
183 return;
184 }
185
186 m_destination->withdraw(*rrIt,
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400187 [=] {
Junxiao Shi89c0ea02017-03-06 19:52:05 +0000188 NFD_LOG_DEBUG("withdraw " << rrIt->prefix << " success");
189 m_rrs.erase(rrIt);
190 },
Davide Pesaventoe4b22382018-06-10 14:37:24 -0400191 [=] (const std::string& msg) {
Junxiao Shi89c0ea02017-03-06 19:52:05 +0000192 NFD_LOG_DEBUG("withdraw " << rrIt->prefix << " failure " << msg);
193 rrIt->retryDelay = std::min(RETRY_DELAY_MAX, rrIt->retryDelay * 2);
Davide Pesaventoe1bdc082018-10-11 21:20:23 -0400194 rrIt->retryEvt = m_scheduler.scheduleEvent(randomizeTimer(rrIt->retryDelay),
195 [=] { withdraw(rrIt); });
Junxiao Shi89c0ea02017-03-06 19:52:05 +0000196 });
197}
198
199} // namespace rib
200} // namespace nfd