blob: d5f26f2d51acd787108b024d320e696faec05033 [file] [log] [blame]
Alexander Afanasyev3ecec502014-04-16 13:42:44 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014 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 "rib-manager.hpp"
Alexander Afanasyev89cf5e02014-04-17 12:08:57 -070027#include "core/logger.hpp"
Alexander Afanasyev3ecec502014-04-16 13:42:44 -070028
29namespace nfd {
30namespace rib {
31
Alexander Afanasyev89cf5e02014-04-17 12:08:57 -070032NFD_LOG_INIT("RibManager");
33
Alexander Afanasyev3ecec502014-04-16 13:42:44 -070034const Name RibManager::COMMAND_PREFIX = "/localhost/nrd";
35const Name RibManager::REMOTE_COMMAND_PREFIX = "/localhop/nrd";
36
37const size_t RibManager::COMMAND_UNSIGNED_NCOMPS =
38 RibManager::COMMAND_PREFIX.size() +
39 1 + // verb
40 1; // verb options
41
42const size_t RibManager::COMMAND_SIGNED_NCOMPS =
43 RibManager::COMMAND_UNSIGNED_NCOMPS +
44 4; // (timestamp, nonce, signed info tlv, signature tlv)
45
46const RibManager::VerbAndProcessor RibManager::COMMAND_VERBS[] =
47 {
48 VerbAndProcessor(
49 Name::Component("register"),
50 &RibManager::insertEntry
51 ),
52
53 VerbAndProcessor(
54 Name::Component("unregister"),
55 &RibManager::deleteEntry
56 ),
57 };
58
59RibManager::RibManager()
60 : m_face(new ndn::Face())
61 , m_nfdController(new ndn::nfd::Controller(*m_face))
62 , m_validator(m_face)
63 , m_faceMonitor(*m_face)
64 , m_verbDispatch(COMMAND_VERBS,
65 COMMAND_VERBS + (sizeof(COMMAND_VERBS) / sizeof(VerbAndProcessor)))
66{
67}
68
69void
70RibManager::registerWithNfd()
71{
72 //check whether the components of localhop and localhost prefixes are same
73 BOOST_ASSERT(COMMAND_PREFIX.size() == REMOTE_COMMAND_PREFIX.size());
74
Alexander Afanasyev89cf5e02014-04-17 12:08:57 -070075 NFD_LOG_INFO("Setting interest filter on: " << COMMAND_PREFIX.toUri());
Alexander Afanasyev3ecec502014-04-16 13:42:44 -070076 m_face->setController(m_nfdController);
77 m_face->setInterestFilter(COMMAND_PREFIX.toUri(),
78 bind(&RibManager::onRibRequest, this, _2),
79 bind(&RibManager::setInterestFilterFailed, this, _1, _2));
80
Alexander Afanasyev89cf5e02014-04-17 12:08:57 -070081 NFD_LOG_INFO("Setting interest filter on: " << REMOTE_COMMAND_PREFIX.toUri());
Alexander Afanasyev3ecec502014-04-16 13:42:44 -070082 m_face->setInterestFilter(REMOTE_COMMAND_PREFIX.toUri(),
83 bind(&RibManager::onRibRequest, this, _2),
84 bind(&RibManager::setInterestFilterFailed, this, _1, _2));
85
Alexander Afanasyev89cf5e02014-04-17 12:08:57 -070086 NFD_LOG_INFO("Start monitoring face create/destroy events");
Alexander Afanasyev3ecec502014-04-16 13:42:44 -070087 m_faceMonitor.addSubscriber(boost::bind(&RibManager::onNotification, this, _1));
88 m_faceMonitor.startNotifications();
89}
90
91void
92RibManager::setConfigFile(ConfigFile& configFile)
93{
94 configFile.addSectionHandler("security",
95 bind(&RibManager::onConfig, this, _1, _2, _3));
96}
97
98void
99RibManager::onConfig(const ConfigSection& configSection,
100 bool isDryRun,
101 const std::string& filename)
102{
103 /// \todo remove check after validator-conf replaces settings on each load
104 if (!isDryRun)
105 m_validator.load(configSection, filename);
106}
107
108void
109RibManager::setInterestFilterFailed(const Name& name, const std::string& msg)
110{
Alexander Afanasyev89cf5e02014-04-17 12:08:57 -0700111 NFD_LOG_ERROR("Error in setting interest filter (" << name << "): " << msg);
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700112 m_face->shutdown();
113}
114
115void
116RibManager::sendResponse(const Name& name,
117 const ControlResponse& response)
118{
119 const Block& encodedControl = response.wireEncode();
120
121 Data responseData(name);
122 responseData.setContent(encodedControl);
123
124 m_keyChain.sign(responseData);
125 m_face->put(responseData);
126}
127
128void
129RibManager::sendResponse(const Name& name,
130 uint32_t code,
131 const std::string& text)
132{
133 ControlResponse response(code, text);
134 sendResponse(name, response);
135}
136
137void
138RibManager::onRibRequest(const Interest& request)
139{
140 m_validator.validate(request,
141 bind(&RibManager::onRibRequestValidated, this, _1),
142 bind(&RibManager::onRibRequestValidationFailed, this, _1, _2));
143}
144
145void
146RibManager::onRibRequestValidated(const shared_ptr<const Interest>& request)
147{
148 const Name& command = request->getName();
149
150 //REMOTE_COMMAND_PREFIX number of componenets are same as
151 // NRD_COMMAND_PREFIX's so no extra checks are required.
152 const Name::Component& verb = command.get(COMMAND_PREFIX.size());
153 VerbDispatchTable::const_iterator verbProcessor = m_verbDispatch.find(verb);
154
155 if (verbProcessor != m_verbDispatch.end())
156 {
Alexander Afanasyev89cf5e02014-04-17 12:08:57 -0700157 NFD_LOG_TRACE("Processing '" << verb << "' verb");
158
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700159 PrefixRegOptions options;
160 if (!extractOptions(*request, options))
161 {
Alexander Afanasyev89cf5e02014-04-17 12:08:57 -0700162 NFD_LOG_DEBUG("Error while extracting options, returning malformed command");
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700163 sendResponse(command, 400, "Malformed command");
164 return;
165 }
166
Alexander Afanasyev89cf5e02014-04-17 12:08:57 -0700167 NFD_LOG_DEBUG("Received options (name, faceid, cost): " << options.getName()
168 << ", " << options.getFaceId() << ", " << options.getCost());
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700169
170 ControlResponse response;
171 (verbProcessor->second)(this, *request, options);
172 }
173 else
174 {
Alexander Afanasyev89cf5e02014-04-17 12:08:57 -0700175 NFD_LOG_DEBUG("Unsupported command: " << verb);
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700176 sendResponse(request->getName(), 501, "Unsupported command");
177 }
178}
179
180void
181RibManager::onRibRequestValidationFailed(const shared_ptr<const Interest>& request,
182 const std::string& failureInfo)
183{
Alexander Afanasyev89cf5e02014-04-17 12:08:57 -0700184 NFD_LOG_DEBUG("RibRequestValidationFailed: " << failureInfo);
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700185 sendResponse(request->getName(), 403, failureInfo);
186}
187
188bool
189RibManager::extractOptions(const Interest& request,
190 PrefixRegOptions& extractedOptions)
191{
192 // const Name& command = request.getName();
193 //REMOTE_COMMAND_PREFIX is same in size of NRD_COMMAND_PREFIX
194 //so no extra processing is required.
195 const size_t optionCompIndex = COMMAND_PREFIX.size() + 1;
196
197 try
198 {
199 Block rawOptions = request.getName()[optionCompIndex].blockFromValue();
200 extractedOptions.wireDecode(rawOptions);
201 }
202 catch (const ndn::Tlv::Error& e)
203 {
204 return false;
205 }
206
207 if (extractedOptions.getFaceId() == 0)
208 {
Alexander Afanasyev89cf5e02014-04-17 12:08:57 -0700209 NFD_LOG_TRACE("IncomingFaceId: " << request.getIncomingFaceId());
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700210 extractedOptions.setFaceId(request.getIncomingFaceId());
211 }
212 return true;
213}
214
215void
216RibManager::onCommandError(uint32_t code, const std::string& error,
217 const Interest& request,
218 const PrefixRegOptions& options)
219{
Alexander Afanasyev89cf5e02014-04-17 12:08:57 -0700220 NFD_LOG_ERROR("NFD returned an error: " << error << " (code: " << code << ")");
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700221
222 ControlResponse response;
223
224 if (code == 404)
225 {
226 response.setCode(code);
227 response.setText(error);
228 }
229 else
230 {
231 response.setCode(533);
232 std::ostringstream os;
233 os << "Failure to update NFD " << "(NFD Error: " << code << " " << error << ")";
234 response.setText(os.str());
235 }
236
237 sendResponse(request.getName(), response);
238 m_managedRib.erase(options);
239}
240
241void
242RibManager::onUnRegSuccess(const Interest& request, const PrefixRegOptions& options)
243{
244 ControlResponse response;
245
246 response.setCode(200);
247 response.setText("Success");
248 response.setBody(options.wireEncode());
249
Alexander Afanasyev89cf5e02014-04-17 12:08:57 -0700250 NFD_LOG_DEBUG("onUnRegSuccess: Name unregistered (" << options.getName()
251 << ", " << options.getFaceId() << ")");
252
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700253 sendResponse(request.getName(), response);
254 m_managedRib.erase(options);
255}
256
257void
258RibManager::onRegSuccess(const Interest& request, const PrefixRegOptions& options)
259{
260 ControlResponse response;
261
262 response.setCode(200);
263 response.setText("Success");
264 response.setBody(options.wireEncode());
265
Alexander Afanasyev89cf5e02014-04-17 12:08:57 -0700266 NFD_LOG_DEBUG("onRegSuccess: Name registered (" << options.getName() << ", "
267 << options.getFaceId() << ")");
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700268 sendResponse(request.getName(), response);
269}
270
271void
272RibManager::insertEntry(const Interest& request, const PrefixRegOptions& options)
273{
274 // For right now, just pass the options to fib as it is,
275 // without processing flags. Later options will be first added to
276 // Rib tree, then nrd will generate fib updates based on flags and then
277 // will add next hops one by one..
278 m_managedRib.insert(options);
279 m_nfdController->start<ndn::nfd::FibAddNextHopCommand>(
280 ControlParameters()
281 .setName(options.getName())
282 .setFaceId(options.getFaceId())
283 .setCost(options.getCost()),
284 bind(&RibManager::onRegSuccess, this, request, options),
285 bind(&RibManager::onCommandError, this, _1, _2, request, options));
286}
287
288void
289RibManager::deleteEntry(const Interest& request, const PrefixRegOptions& options)
290{
291 m_nfdController->start<ndn::nfd::FibRemoveNextHopCommand>(
292 ControlParameters()
293 .setName(options.getName())
294 .setFaceId(options.getFaceId()),
295 bind(&RibManager::onUnRegSuccess, this, request, options),
296 bind(&RibManager::onCommandError, this, _1, _2, request, options));
297}
298
299boost::asio::io_service&
300RibManager::getIoService()
301{
302 /// \todo Switch face to use global io service (needs library update)
303 return *m_face->ioService();
304}
305
306void
307RibManager::onControlHeaderSuccess()
308{
Alexander Afanasyev89cf5e02014-04-17 12:08:57 -0700309 NFD_LOG_DEBUG("Local control header enabled");
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700310}
311
312void
313RibManager::onControlHeaderError(uint32_t code, const std::string& reason)
314{
Alexander Afanasyev89cf5e02014-04-17 12:08:57 -0700315 NFD_LOG_ERROR("Error: couldn't enable local control header "
316 << "(code: " << code << ", info: " << reason << ")");
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700317 m_face->shutdown();
318}
319
320void
321RibManager::enableLocalControlHeader()
322{
323 m_nfdController->start<ndn::nfd::FaceEnableLocalControlCommand>(
324 ControlParameters()
325 .setLocalControlFeature(ndn::nfd::LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID),
326 bind(&RibManager::onControlHeaderSuccess, this),
327 bind(&RibManager::onControlHeaderError, this, _1, _2));
328}
329
330void
331RibManager::onNotification(const FaceEventNotification& notification)
332{
333 /// \todo A notification can be missed, in this case check Facelist
Alexander Afanasyev89cf5e02014-04-17 12:08:57 -0700334 NFD_LOG_TRACE("onNotification: " << notification);
Alexander Afanasyev3ecec502014-04-16 13:42:44 -0700335 if (notification.getKind() == ndn::nfd::FACE_EVENT_DESTROYED) { //face destroyed
336 m_managedRib.erase(notification.getFaceId());
337 }
338}
339
340} // namespace rib
341} // namespace nfd