blob: e5b517539cd94018e35d87c5a441692a5b358d63 [file] [log] [blame]
Junxiao Shib8590312016-12-29 21:22:25 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Junxiao Shi38b24c72017-01-05 02:59:31 +00003 * Copyright (c) 2014-2017, Regents of the University of California,
Junxiao Shib8590312016-12-29 21:22:25 +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 "face-system.hpp"
27#include "core/logger.hpp"
Junxiao Shib8590312016-12-29 21:22:25 +000028#include "fw/face-table.hpp"
29
30// ProtocolFactory includes, sorted alphabetically
31#ifdef HAVE_LIBPCAP
32#include "ethernet-factory.hpp"
Junxiao Shib8590312016-12-29 21:22:25 +000033#endif // HAVE_LIBPCAP
34#include "tcp-factory.hpp"
35#include "udp-factory.hpp"
36#ifdef HAVE_UNIX_SOCKETS
37#include "unix-stream-factory.hpp"
38#endif // HAVE_UNIX_SOCKETS
39#ifdef HAVE_WEBSOCKET
40#include "websocket-factory.hpp"
41#endif // HAVE_WEBSOCKET
42
43namespace nfd {
44namespace face {
45
46NFD_LOG_INIT("FaceSystem");
47
48FaceSystem::FaceSystem(FaceTable& faceTable)
49 : m_faceTable(faceTable)
50{
Junxiao Shi38b24c72017-01-05 02:59:31 +000051 ///\todo #3904 make a registry, and construct instances from registry
Junxiao Shi7003c602017-01-10 13:35:28 +000052
53#ifdef HAVE_LIBPCAP
54 m_factories["ether"] = make_shared<EthernetFactory>();
55#endif // HAVE_LIBPCAP
56
Junxiao Shi38b24c72017-01-05 02:59:31 +000057 m_factories["tcp"] = make_shared<TcpFactory>();
Junxiao Shi406deb52017-01-05 20:07:44 +000058
59#ifdef HAVE_UNIX_SOCKETS
60 m_factories["unix"] = make_shared<UnixStreamFactory>();
61#endif // HAVE_UNIX_SOCKETS
Junxiao Shi3409cd32017-01-18 15:31:27 +000062
63#ifdef HAVE_WEBSOCKET
64 m_factories["websocket"] = make_shared<WebSocketFactory>();
65#endif // HAVE_WEBSOCKET
Junxiao Shib8590312016-12-29 21:22:25 +000066}
67
68std::set<const ProtocolFactory*>
69FaceSystem::listProtocolFactories() const
70{
71 std::set<const ProtocolFactory*> factories;
Junxiao Shi38b24c72017-01-05 02:59:31 +000072 for (const auto& p : m_factoryByScheme) {
Junxiao Shib8590312016-12-29 21:22:25 +000073 factories.insert(p.second.get());
74 }
75 return factories;
76}
77
78ProtocolFactory*
Junxiao Shi38b24c72017-01-05 02:59:31 +000079FaceSystem::getFactoryById(const std::string& id)
Junxiao Shib8590312016-12-29 21:22:25 +000080{
Junxiao Shi38b24c72017-01-05 02:59:31 +000081 auto found = m_factories.find(id);
Junxiao Shib8590312016-12-29 21:22:25 +000082 return found == m_factories.end() ? nullptr : found->second.get();
83}
84
Junxiao Shi38b24c72017-01-05 02:59:31 +000085ProtocolFactory*
86FaceSystem::getFactoryByScheme(const std::string& scheme)
87{
88 auto found = m_factoryByScheme.find(scheme);
89 return found == m_factoryByScheme.end() ? nullptr : found->second.get();
90}
91
Junxiao Shib8590312016-12-29 21:22:25 +000092void
93FaceSystem::setConfigFile(ConfigFile& configFile)
94{
95 configFile.addSectionHandler("face_system", bind(&FaceSystem::processConfig, this, _1, _2, _3));
96}
97
98void
99FaceSystem::processConfig(const ConfigSection& configSection, bool isDryRun, const std::string& filename)
100{
Junxiao Shi38b24c72017-01-05 02:59:31 +0000101 ConfigContext context;
102 context.isDryRun = isDryRun;
103 context.addFace = bind(&FaceTable::add, &m_faceTable, _1);
Junxiao Shi7003c602017-01-10 13:35:28 +0000104 context.m_netifs = listNetworkInterfaces();
Junxiao Shi38b24c72017-01-05 02:59:31 +0000105
106 // process sections in protocol factories
107 for (const auto& pair : m_factories) {
108 const std::string& sectionName = pair.first;
109 shared_ptr<ProtocolFactory> factory = pair.second;
110
111 std::set<std::string> oldProvidedSchemes = factory->getProvidedSchemes();
112 factory->processConfig(configSection.get_child_optional(sectionName), context);
113
114 if (!isDryRun) {
115 for (const std::string& scheme : factory->getProvidedSchemes()) {
116 m_factoryByScheme[scheme] = factory;
117 oldProvidedSchemes.erase(scheme);
118 }
119 for (const std::string& scheme : oldProvidedSchemes) {
120 m_factoryByScheme.erase(scheme);
121 }
122 }
123 }
124
125 // process other sections
Junxiao Shib8590312016-12-29 21:22:25 +0000126 std::set<std::string> seenSections;
Junxiao Shi38b24c72017-01-05 02:59:31 +0000127 for (const auto& pair : configSection) {
128 const std::string& sectionName = pair.first;
129 const ConfigSection& subSection = pair.second;
Junxiao Shib8590312016-12-29 21:22:25 +0000130
Junxiao Shi38b24c72017-01-05 02:59:31 +0000131 if (!seenSections.insert(sectionName).second) {
132 BOOST_THROW_EXCEPTION(ConfigFile::Error("Duplicate section face_system." + sectionName));
Junxiao Shib8590312016-12-29 21:22:25 +0000133 }
134
Junxiao Shi38b24c72017-01-05 02:59:31 +0000135 if (m_factories.count(sectionName) > 0) {
136 continue;
Junxiao Shib8590312016-12-29 21:22:25 +0000137 }
Junxiao Shi38b24c72017-01-05 02:59:31 +0000138
139 ///\todo #3521 nicfaces
140
141 ///\todo #3904 process these in protocol factory
Junxiao Shi406deb52017-01-05 20:07:44 +0000142 if (sectionName == "udp") {
Junxiao Shi7003c602017-01-10 13:35:28 +0000143 processSectionUdp(subSection, isDryRun, context.m_netifs);
Junxiao Shib8590312016-12-29 21:22:25 +0000144 }
Junxiao Shib8590312016-12-29 21:22:25 +0000145 else {
Junxiao Shi38b24c72017-01-05 02:59:31 +0000146 BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option face_system." + sectionName));
Junxiao Shib8590312016-12-29 21:22:25 +0000147 }
148 }
149}
150
151void
Junxiao Shib8590312016-12-29 21:22:25 +0000152FaceSystem::processSectionUdp(const ConfigSection& configSection, bool isDryRun,
153 const std::vector<NetworkInterfaceInfo>& nicList)
154{
155 // ; the udp section contains settings of UDP faces and channels
156 // udp
157 // {
158 // port 6363 ; UDP unicast port number
159 // idle_timeout 600 ; idle time (seconds) before closing a UDP unicast face
160 // keep_alive_interval 25 ; interval (seconds) between keep-alive refreshes
161
162 // ; NFD creates one UDP multicast face per NIC
163 // mcast yes ; set to 'no' to disable UDP multicast, default 'yes'
164 // mcast_port 56363 ; UDP multicast port number
165 // mcast_group 224.0.23.170 ; UDP multicast group (IPv4 only)
166 // }
167
168 uint16_t port = 6363;
169 bool enableV4 = true;
170 bool enableV6 = true;
171 size_t timeout = 600;
172 size_t keepAliveInterval = 25;
173 bool useMcast = true;
174 auto mcastGroup = boost::asio::ip::address_v4::from_string("224.0.23.170");
175 uint16_t mcastPort = 56363;
176
177 for (const auto& i : configSection) {
178 if (i.first == "port") {
179 port = ConfigFile::parseNumber<uint16_t>(i, "udp");
180 NFD_LOG_TRACE("UDP unicast port set to " << port);
181 }
182 else if (i.first == "enable_v4") {
183 enableV4 = ConfigFile::parseYesNo(i, "udp");
184 }
185 else if (i.first == "enable_v6") {
186 enableV6 = ConfigFile::parseYesNo(i, "udp");
187 }
188 else if (i.first == "idle_timeout") {
189 try {
190 timeout = i.second.get_value<size_t>();
191 }
192 catch (const boost::property_tree::ptree_bad_data&) {
193 BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option \"" +
194 i.first + "\" in \"udp\" section"));
195 }
196 }
197 else if (i.first == "keep_alive_interval") {
198 try {
199 keepAliveInterval = i.second.get_value<size_t>();
200 /// \todo Make use of keepAliveInterval
201 (void)(keepAliveInterval);
202 }
203 catch (const boost::property_tree::ptree_bad_data&) {
204 BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option \"" +
205 i.first + "\" in \"udp\" section"));
206 }
207 }
208 else if (i.first == "mcast") {
209 useMcast = ConfigFile::parseYesNo(i, "udp");
210 }
211 else if (i.first == "mcast_port") {
212 mcastPort = ConfigFile::parseNumber<uint16_t>(i, "udp");
213 NFD_LOG_TRACE("UDP multicast port set to " << mcastPort);
214 }
215 else if (i.first == "mcast_group") {
216 boost::system::error_code ec;
217 mcastGroup = boost::asio::ip::address_v4::from_string(i.second.get_value<std::string>(), ec);
218 if (ec) {
219 BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option \"" +
220 i.first + "\" in \"udp\" section"));
221 }
222 NFD_LOG_TRACE("UDP multicast group set to " << mcastGroup);
223 }
224 else {
225 BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option \"" +
226 i.first + "\" in \"udp\" section"));
227 }
228 }
229
230 if (!enableV4 && !enableV6) {
231 BOOST_THROW_EXCEPTION(ConfigFile::Error("IPv4 and IPv6 UDP channels have been disabled."
232 " Remove \"udp\" section to disable UDP channels or"
233 " re-enable at least one channel type."));
234 }
235 else if (useMcast && !enableV4) {
236 BOOST_THROW_EXCEPTION(ConfigFile::Error("IPv4 multicast requested, but IPv4 channels"
237 " have been disabled (conflicting configuration options set)"));
238 }
239
240 if (!isDryRun) {
241 shared_ptr<UdpFactory> factory;
242 bool isReload = false;
Junxiao Shi38b24c72017-01-05 02:59:31 +0000243 if (m_factoryByScheme.count("udp") > 0) {
Junxiao Shib8590312016-12-29 21:22:25 +0000244 isReload = true;
Junxiao Shi38b24c72017-01-05 02:59:31 +0000245 factory = static_pointer_cast<UdpFactory>(m_factoryByScheme["udp"]);
Junxiao Shib8590312016-12-29 21:22:25 +0000246 }
247 else {
248 factory = make_shared<UdpFactory>();
Junxiao Shi38b24c72017-01-05 02:59:31 +0000249 m_factoryByScheme.emplace("udp", factory);
Junxiao Shib8590312016-12-29 21:22:25 +0000250 }
251
252 if (!isReload && enableV4) {
253 udp::Endpoint endpoint(boost::asio::ip::udp::v4(), port);
254 shared_ptr<UdpChannel> v4Channel = factory->createChannel(endpoint, time::seconds(timeout));
255 v4Channel->listen(bind(&FaceTable::add, &m_faceTable, _1), nullptr);
256
Junxiao Shi38b24c72017-01-05 02:59:31 +0000257 m_factoryByScheme.emplace("udp4", factory);
Junxiao Shib8590312016-12-29 21:22:25 +0000258 }
259
260 if (!isReload && enableV6) {
261 udp::Endpoint endpoint(boost::asio::ip::udp::v6(), port);
262 shared_ptr<UdpChannel> v6Channel = factory->createChannel(endpoint, time::seconds(timeout));
263 v6Channel->listen(bind(&FaceTable::add, &m_faceTable, _1), nullptr);
264
Junxiao Shi38b24c72017-01-05 02:59:31 +0000265 m_factoryByScheme.emplace("udp6", factory);
Junxiao Shib8590312016-12-29 21:22:25 +0000266 }
267
268 std::set<shared_ptr<Face>> multicastFacesToRemove;
269 for (const auto& i : factory->getMulticastFaces()) {
270 multicastFacesToRemove.insert(i.second);
271 }
272
273 if (useMcast && enableV4) {
274 std::vector<NetworkInterfaceInfo> ipv4MulticastInterfaces;
275 for (const auto& nic : nicList) {
276 if (nic.isUp() && nic.isMulticastCapable() && !nic.ipv4Addresses.empty()) {
277 ipv4MulticastInterfaces.push_back(nic);
278 }
279 }
280
281 bool isNicNameNecessary = false;
282#if defined(__linux__)
283 if (ipv4MulticastInterfaces.size() > 1) {
284 // On Linux if we have more than one MulticastUdpFace
285 // we need to specify the name of the interface
286 isNicNameNecessary = true;
287 }
288#endif
289
290 udp::Endpoint mcastEndpoint(mcastGroup, mcastPort);
291 for (const auto& nic : ipv4MulticastInterfaces) {
292 udp::Endpoint localEndpoint(nic.ipv4Addresses[0], mcastPort);
293 auto newFace = factory->createMulticastFace(localEndpoint, mcastEndpoint,
294 isNicNameNecessary ? nic.name : "");
295 m_faceTable.add(newFace);
296 multicastFacesToRemove.erase(newFace);
297 }
298 }
299
300 for (const auto& face : multicastFacesToRemove) {
301 face->close();
302 }
303 }
304}
305
Junxiao Shib8590312016-12-29 21:22:25 +0000306} // namespace face
307} // namespace nfd