blob: 0e90bd03f5fceb144fbf518407cc9cb1d79e3562 [file] [log] [blame]
Alexander Afanasyev2aa39622014-01-22 11:51:11 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -07003 * 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 *
10 * This file is part of NFD (Named Data Networking Forwarding Daemon).
11 * See AUTHORS.md for complete list of NFD authors and contributors.
12 *
13 * NFD is free software: you can redistribute it and/or modify it under the terms
14 * of the GNU General Public License as published by the Free Software Foundation,
15 * either version 3 of the License, or (at your option) any later version.
16 *
17 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
18 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
19 * PURPOSE. See the GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along with
22 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
23 **/
Alexander Afanasyev2aa39622014-01-22 11:51:11 -080024
Junxiao Shi09bf7c42014-01-31 11:10:25 -070025#include <getopt.h>
Junxiao Shi98e29f42014-03-31 10:27:26 -070026#include <boost/filesystem.hpp>
27
Alexander Afanasyevb47d5382014-05-05 14:35:03 -070028#include "version.hpp"
Junxiao Shi09bf7c42014-01-31 11:10:25 -070029#include "core/logger.hpp"
Junxiao Shi98e29f42014-03-31 10:27:26 -070030#include "core/global-io.hpp"
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060031#include "core/privilege-helper.hpp"
Junxiao Shi09bf7c42014-01-31 11:10:25 -070032#include "fw/forwarder.hpp"
33#include "mgmt/internal-face.hpp"
Steve DiBenedetto214563c2014-02-03 19:20:36 -070034#include "mgmt/fib-manager.hpp"
Steve DiBenedettoabe9e972014-02-20 15:37:04 -070035#include "mgmt/face-manager.hpp"
Steve DiBenedetto5330e0d2014-03-05 21:52:51 -070036#include "mgmt/strategy-choice-manager.hpp"
Junxiao Shiea48d8b2014-03-16 13:53:47 -070037#include "mgmt/status-server.hpp"
Alexander Afanasyev613e2a92014-04-15 13:36:58 -070038#include "core/config-file.hpp"
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060039#include "mgmt/general-config-section.hpp"
Alexander Afanasyevc78b1412014-02-19 14:08:26 -080040
Junxiao Shi09bf7c42014-01-31 11:10:25 -070041namespace nfd {
42
Alexander Afanasyev89cf5e02014-04-17 12:08:57 -070043NFD_LOG_INIT("NFD");
Junxiao Shi09bf7c42014-01-31 11:10:25 -070044
45struct ProgramOptions
Alexander Afanasyev2aa39622014-01-22 11:51:11 -080046{
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -070047 bool showUsage;
Alexander Afanasyevb47d5382014-05-05 14:35:03 -070048 bool showVersion;
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060049 bool showModules;
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -070050 std::string config;
Junxiao Shi09bf7c42014-01-31 11:10:25 -070051};
52
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -070053class Nfd : noncopyable
Junxiao Shi09bf7c42014-01-31 11:10:25 -070054{
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -070055public:
Alexander Afanasyev5959b012014-06-02 19:18:12 +030056 explicit
57 Nfd(const std::string& configFile)
58 : m_configFile(configFile)
59 , m_originalStreamBuf(0)
60 {
61 }
62
63 ~Nfd()
64 {
65 if (static_cast<bool>(m_originalStreamBuf)) {
66 std::clog.rdbuf(m_originalStreamBuf);
67 }
68 }
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060069
70 void
Alexander Afanasyev5959b012014-06-02 19:18:12 +030071 initialize()
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -070072 {
Alexander Afanasyev5959b012014-06-02 19:18:12 +030073 initializeLogging();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060074
75 m_forwarder = make_shared<Forwarder>();
76
Alexander Afanasyev5959b012014-06-02 19:18:12 +030077 initializeManagement();
Steve DiBenedetto24b9a642014-04-07 15:45:39 -060078
79 PrivilegeHelper::drop();
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060080 }
81
82
83 void
Alexander Afanasyev5959b012014-06-02 19:18:12 +030084 initializeLogging()
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060085 {
Steve DiBenedetto34c95f72014-04-17 20:56:00 -060086 ConfigFile config(&ConfigFile::ignoreUnknownSection);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060087 LoggerFactory::getInstance().setConfigFile(config);
88
Alexander Afanasyev5959b012014-06-02 19:18:12 +030089 config.parse(m_configFile, true);
90 config.parse(m_configFile, false);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -060091 }
92
Steve DiBenedetto34c95f72014-04-17 20:56:00 -060093 class IgnoreRibAndLogSections
94 {
95 public:
96 void
97 operator()(const std::string& filename,
98 const std::string& sectionName,
99 const ConfigSection& section,
100 bool isDryRun)
101
102 {
103 // Ignore "log" and sections beginning with "rib_" (intended for rib manager),
104 // but raise an error if we're missing a handler for an NFD section.
105
Yingdi Yue5224e92014-04-29 18:04:02 -0700106 if (sectionName.find("rib") == 0 || sectionName == "log")
Steve DiBenedetto34c95f72014-04-17 20:56:00 -0600107 {
108 // do nothing
109 }
110 else
111 {
112 // missing NFD section
113 ConfigFile::throwErrorOnUnknownSection(filename, sectionName, section, isDryRun);
114 }
115 }
116 };
117
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600118 void
Alexander Afanasyev5959b012014-06-02 19:18:12 +0300119 initializeManagement()
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600120 {
121 m_internalFace = make_shared<InternalFace>();
122
Alexander Afanasyevf6980282014-05-13 18:28:40 -0700123 m_fibManager = make_shared<FibManager>(ref(m_forwarder->getFib()),
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600124 bind(&Forwarder::getFace, m_forwarder.get(), _1),
125 m_internalFace);
126
Alexander Afanasyevf6980282014-05-13 18:28:40 -0700127 m_faceManager = make_shared<FaceManager>(ref(m_forwarder->getFaceTable()),
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600128 m_internalFace);
129
130 m_strategyChoiceManager =
Alexander Afanasyevf6980282014-05-13 18:28:40 -0700131 make_shared<StrategyChoiceManager>(ref(m_forwarder->getStrategyChoice()),
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600132 m_internalFace);
133
134 m_statusServer = make_shared<StatusServer>(m_internalFace,
Alexander Afanasyevf6980282014-05-13 18:28:40 -0700135 ref(*m_forwarder));
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600136
Steve DiBenedetto34c95f72014-04-17 20:56:00 -0600137 ConfigFile config((IgnoreRibAndLogSections()));
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600138
139 general::setConfigFile(config);
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700140 m_internalFace->getValidator().setConfigFile(config);
Junxiao Shi09bf7c42014-01-31 11:10:25 -0700141
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600142 m_forwarder->addFace(m_internalFace);
Junxiao Shic041ca32014-02-25 20:01:15 -0700143
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600144 m_faceManager->setConfigFile(config);
145
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700146 // parse config file
Alexander Afanasyev5959b012014-06-02 19:18:12 +0300147 config.parse(m_configFile, true);
148 config.parse(m_configFile, false);
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700149
150 // add FIB entry for NFD Management Protocol
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600151 shared_ptr<fib::Entry> entry = m_forwarder->getFib().insert("/localhost/nfd").first;
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700152 entry->addNextHop(m_internalFace, 0);
153 }
154
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700155 static void
156 printUsage(std::ostream& os, const std::string& programName)
157 {
158 os << "Usage: \n"
159 << " " << programName << " [options]\n"
160 << "\n"
161 << "Run NFD forwarding daemon\n"
162 << "\n"
163 << "Options:\n"
Alexander Afanasyevb47d5382014-05-05 14:35:03 -0700164 << " [--help] - print this help message\n"
165 << " [--version] - print version and exit\n"
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600166 << " [--modules] - list available logging modules\n"
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700167 << " [--config /path/to/nfd.conf] - path to configuration file "
168 << "(default: " << DEFAULT_CONFIG_FILE << ")\n"
169 ;
170 }
171
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600172 static void
173 printModules(std::ostream& os)
174 {
175 using namespace std;
176
177 os << "Available logging modules: \n";
178
179 list<string> modules(LoggerFactory::getInstance().getModules());
180 for (list<string>::const_iterator i = modules.begin(); i != modules.end(); ++i)
181 {
182 os << *i << "\n";
183 }
184 }
185
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700186 static bool
187 parseCommandLine(int argc, char** argv, ProgramOptions& options)
188 {
189 options.showUsage = false;
Alexander Afanasyevb47d5382014-05-05 14:35:03 -0700190 options.showVersion = false;
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600191 options.showModules = false;
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700192 options.config = DEFAULT_CONFIG_FILE;
193
194 while (true) {
195 int optionIndex = 0;
196 static ::option longOptions[] = {
197 { "help" , no_argument , 0, 0 },
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600198 { "modules", no_argument , 0, 0 },
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700199 { "config" , required_argument, 0, 0 },
Alexander Afanasyevb47d5382014-05-05 14:35:03 -0700200 { "version", no_argument , 0, 0 },
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700201 { 0 , 0 , 0, 0 }
202 };
203 int c = getopt_long_only(argc, argv, "", longOptions, &optionIndex);
204 if (c == -1)
205 break;
206
207 switch (c) {
Alexander Afanasyevb47d5382014-05-05 14:35:03 -0700208 case 0:
209 switch (optionIndex) {
210 case 0: // help
211 options.showUsage = true;
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700212 break;
Alexander Afanasyevb47d5382014-05-05 14:35:03 -0700213 case 1: // modules
214 options.showModules = true;
215 break;
216 case 2: // config
217 options.config = ::optarg;
218 break;
219 case 3: // version
220 options.showVersion = true;
221 break;
222 default:
223 return false;
224 }
225 break;
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700226 }
Junxiao Shi09bf7c42014-01-31 11:10:25 -0700227 }
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700228 return true;
Junxiao Shi09bf7c42014-01-31 11:10:25 -0700229 }
Steve DiBenedetto2c2b8892014-02-27 11:46:48 -0700230
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700231 void
232 terminate(const boost::system::error_code& error,
233 int signalNo,
234 boost::asio::signal_set& signalSet)
235 {
236 if (error)
237 return;
Junxiao Shi09bf7c42014-01-31 11:10:25 -0700238
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700239 if (signalNo == SIGINT ||
240 signalNo == SIGTERM)
241 {
242 getGlobalIoService().stop();
Alexander Afanasyev89cf5e02014-04-17 12:08:57 -0700243 NFD_LOG_INFO("Caught signal '" << strsignal(signalNo) << "', exiting...");
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700244 }
245 else
246 {
Alexander Afanasyevf6980282014-05-13 18:28:40 -0700247 signalSet.async_wait(bind(&Nfd::terminate, this, _1, _2, ref(signalSet)));
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700248 }
Junxiao Shiea48d8b2014-03-16 13:53:47 -0700249 }
Steve DiBenedetto84da5bf2014-03-11 14:51:29 -0600250
Alexander Afanasyev5959b012014-06-02 19:18:12 +0300251 void
252 reload(const boost::system::error_code& error,
253 int signalNo,
254 boost::asio::signal_set& signalSet)
255 {
256 if (error)
257 return;
258
259 NFD_LOG_INFO("Caught signal '" << strsignal(signalNo));
260
261 ////////////////////////
262 // Reload config file //
263 ////////////////////////
264
265 // Logging
266 initializeLogging();
267 /// \todo Reopen log file
268
269 // Other stuff
270 ConfigFile config((IgnoreRibAndLogSections()));
271
272 general::setConfigFile(config);
273
274 m_internalFace->getValidator().setConfigFile(config);
275 m_faceManager->setConfigFile(config);
276
277 config.parse(m_configFile, false);
278
279 ////////////////////////
280
281 signalSet.async_wait(bind(&Nfd::reload, this, _1, _2, ref(signalSet)));
282 }
283
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700284private:
Alexander Afanasyev5959b012014-06-02 19:18:12 +0300285 std::string m_configFile;
286
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600287 shared_ptr<Forwarder> m_forwarder;
Steve DiBenedetto84da5bf2014-03-11 14:51:29 -0600288
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600289 shared_ptr<InternalFace> m_internalFace;
290 shared_ptr<FibManager> m_fibManager;
291 shared_ptr<FaceManager> m_faceManager;
292 shared_ptr<StrategyChoiceManager> m_strategyChoiceManager;
293 shared_ptr<StatusServer> m_statusServer;
Alexander Afanasyev5959b012014-06-02 19:18:12 +0300294
295 shared_ptr<std::ofstream> m_logFile;
296 std::basic_streambuf<char>* m_originalStreamBuf;
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700297};
Junxiao Shi09bf7c42014-01-31 11:10:25 -0700298
299} // namespace nfd
300
301int
302main(int argc, char** argv)
303{
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700304 using namespace nfd;
Junxiao Shiea48d8b2014-03-16 13:53:47 -0700305
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700306 ProgramOptions options;
307 bool isCommandLineValid = Nfd::parseCommandLine(argc, argv, options);
308 if (!isCommandLineValid) {
309 Nfd::printUsage(std::cerr, argv[0]);
310 return 1;
311 }
Alexander Afanasyevb47d5382014-05-05 14:35:03 -0700312
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700313 if (options.showUsage) {
314 Nfd::printUsage(std::cout, argv[0]);
315 return 0;
316 }
317
Alexander Afanasyevb47d5382014-05-05 14:35:03 -0700318 if (options.showVersion) {
319 std::cout << NFD_VERSION_BUILD_STRING << std::endl;
320 return 0;
321 }
322
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600323 if (options.showModules) {
324 Nfd::printModules(std::cout);
325 return 0;
326 }
327
Alexander Afanasyev5959b012014-06-02 19:18:12 +0300328 Nfd nfdInstance(options.config);
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600329
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700330 try {
Alexander Afanasyev5959b012014-06-02 19:18:12 +0300331 nfdInstance.initialize();
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700332 }
333 catch (boost::filesystem::filesystem_error& e) {
334 if (e.code() == boost::system::errc::permission_denied) {
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600335 NFD_LOG_FATAL("Permissions denied for " << e.path1() << ". " <<
336 argv[0] << " should be run as superuser");
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700337 }
338 else {
339 NFD_LOG_FATAL(e.what());
340 }
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600341 return 1;
342 }
343 catch (const std::exception& e) {
344 NFD_LOG_FATAL(e.what());
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700345 return 2;
346 }
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600347 catch (const PrivilegeHelper::Error& e) {
348 // PrivilegeHelper::Errors do not inherit from std::exception
349 // and represent seteuid/gid failures
350
351 NFD_LOG_FATAL(e.what());
352 return 3;
353 }
354
Alexander Afanasyev5959b012014-06-02 19:18:12 +0300355 boost::asio::signal_set terminationSignalSet(getGlobalIoService());
356 terminationSignalSet.add(SIGINT);
357 terminationSignalSet.add(SIGTERM);
358 terminationSignalSet.async_wait(bind(&Nfd::terminate, &nfdInstance, _1, _2,
359 ref(terminationSignalSet)));
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600360
Alexander Afanasyev5959b012014-06-02 19:18:12 +0300361 boost::asio::signal_set reloadSignalSet(getGlobalIoService());
362 reloadSignalSet.add(SIGHUP);
363 reloadSignalSet.async_wait(bind(&Nfd::reload, &nfdInstance, _1, _2,
364 ref(reloadSignalSet)));
Steve DiBenedettobf6a93d2014-03-21 14:03:02 -0600365
366 try {
367 getGlobalIoService().run();
368 }
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600369 catch (const std::exception& e) {
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700370 NFD_LOG_FATAL(e.what());
Steve DiBenedetto24b9a642014-04-07 15:45:39 -0600371 return 4;
372 }
373 catch (const PrivilegeHelper::Error& e) {
374 NFD_LOG_FATAL(e.what());
375 return 5;
Alexander Afanasyev5a4388a2014-03-27 18:02:55 -0700376 }
377
378 return 0;
379}