face: parse face_system.netdev_bound config section
refs #3521
Change-Id: I803a1651d5b44e021ec7bedb8001e216c849b9ab
diff --git a/daemon/face/face-system.cpp b/daemon/face/face-system.cpp
index 872efef..79880da 100644
--- a/daemon/face/face-system.cpp
+++ b/daemon/face/face-system.cpp
@@ -25,6 +25,7 @@
#include "face-system.hpp"
#include "protocol-factory.hpp"
+#include "netdev-bound.hpp"
#include "core/global-io.hpp"
#include "fw/face-table.hpp"
@@ -33,6 +34,9 @@
NFD_LOG_INIT(FaceSystem);
+static const std::string SECTION_GENERAL = "general";
+static const std::string SECTION_NETDEVBOUND = "netdev_bound";
+
FaceSystem::FaceSystem(FaceTable& faceTable, shared_ptr<ndn::net::NetworkMonitor> netmon)
: m_faceTable(faceTable)
, m_netmon(std::move(netmon))
@@ -42,6 +46,8 @@
NFD_LOG_TRACE("creating factory " << id);
m_factories[id] = ProtocolFactory::create(id, pfCtorParams);
}
+
+ m_netdevBound = make_unique<NetdevBound>(pfCtorParams, *this);
}
ProtocolFactoryCtorParams
@@ -77,6 +83,12 @@
return found == m_factoryByScheme.end() ? nullptr : found->second;
}
+bool
+FaceSystem::hasFactoryForScheme(const std::string& scheme) const
+{
+ return m_factoryByScheme.count(scheme) > 0;
+}
+
void
FaceSystem::setConfigFile(ConfigFile& configFile)
{
@@ -90,7 +102,7 @@
context.isDryRun = isDryRun;
// process general protocol factory config section
- auto generalSection = configSection.get_child_optional("general");
+ auto generalSection = configSection.get_child_optional(SECTION_GENERAL);
if (generalSection) {
for (const auto& pair : *generalSection) {
const std::string& key = pair.first;
@@ -103,7 +115,7 @@
}
}
- // process sections in protocol factories
+ // process in protocol factories
for (const auto& pair : m_factories) {
const std::string& sectionName = pair.first;
ProtocolFactory* factory = pair.second.get();
@@ -127,6 +139,10 @@
}
}
+ // process netdev_bound section, after factories start providing *+dev schemes
+ auto netdevBoundSection = configSection.get_child_optional(SECTION_NETDEVBOUND);
+ m_netdevBound->processConfig(netdevBoundSection, context);
+
// process other sections
std::set<std::string> seenSections;
for (const auto& pair : configSection) {
@@ -137,12 +153,11 @@
BOOST_THROW_EXCEPTION(ConfigFile::Error("Duplicate section face_system." + sectionName));
}
- if (sectionName == "general" || m_factories.count(sectionName) > 0) {
+ if (sectionName == SECTION_GENERAL || sectionName == SECTION_NETDEVBOUND ||
+ m_factories.count(sectionName) > 0) {
continue;
}
- ///\todo #3521 nicfaces
-
BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option face_system." + sectionName));
}
}
diff --git a/daemon/face/face-system.hpp b/daemon/face/face-system.hpp
index 18da37e..833da1b 100644
--- a/daemon/face/face-system.hpp
+++ b/daemon/face/face-system.hpp
@@ -39,6 +39,7 @@
namespace face {
+class NetdevBound;
class ProtocolFactory;
struct ProtocolFactoryCtorParams;
@@ -69,6 +70,9 @@
ProtocolFactory*
getFactoryByScheme(const std::string& scheme);
+ bool
+ hasFactoryForScheme(const std::string& scheme) const;
+
FaceTable&
getFaceTable()
{
@@ -109,6 +113,7 @@
/** \brief config section name => protocol factory
*/
std::map<std::string, unique_ptr<ProtocolFactory>> m_factories;
+ unique_ptr<NetdevBound> m_netdevBound;
private:
/** \brief scheme => protocol factory
@@ -118,7 +123,6 @@
std::map<std::string, ProtocolFactory*> m_factoryByScheme;
FaceTable& m_faceTable;
-
shared_ptr<ndn::net::NetworkMonitor> m_netmon;
};
diff --git a/daemon/face/netdev-bound.cpp b/daemon/face/netdev-bound.cpp
new file mode 100644
index 0000000..a47bd43
--- /dev/null
+++ b/daemon/face/netdev-bound.cpp
@@ -0,0 +1,150 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2018, Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology,
+ * The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "netdev-bound.hpp"
+#include "face-system.hpp"
+#include "core/logger.hpp"
+
+namespace nfd {
+namespace face {
+
+NFD_LOG_INIT(NetdevBound);
+
+NetdevBound::NetdevBound(const ProtocolFactoryCtorParams& params, const FaceSystem& faceSystem)
+ : m_faceSystem(faceSystem)
+ , m_addFace(params.addFace)
+ , m_netmon(params.netmon)
+{
+}
+
+void
+NetdevBound::processConfig(OptionalConfigSection configSection,
+ FaceSystem::ConfigContext& context)
+{
+ std::vector<Rule> rules;
+ if (configSection) {
+ int ruleIndex = 0;
+ for (const auto& pair : *configSection) {
+ const std::string& key = pair.first;
+ const ConfigSection& value = pair.second;
+ if (key == "rule") {
+ rules.push_back(parseRule(ruleIndex++, value));
+ }
+ else {
+ BOOST_THROW_EXCEPTION(ConfigFile::Error(
+ "Unrecognized option face_system.netdev_bound." + key));
+ }
+ }
+ }
+
+ if (context.isDryRun) {
+ return;
+ }
+
+ ///\todo #3521 this should be verified in dry-run, but PFs won't publish their *+dev schemes
+ /// in dry-run
+ for (size_t i = 0; i < rules.size(); ++i) {
+ const Rule& rule = rules[i];
+ for (const FaceUri& remote : rule.remotes) {
+ std::string devScheme = remote.getScheme() + "+dev";
+ if (!m_faceSystem.hasFactoryForScheme(devScheme)) {
+ BOOST_THROW_EXCEPTION(RuleParseError(
+ i, "scheme " + devScheme + " for " + remote.toString() + " is unavailable"));
+ }
+ }
+ }
+ NFD_LOG_DEBUG("processConfig: processed " << rules.size() << " rules");
+
+ m_rules.swap(rules);
+ std::map<Key, shared_ptr<Face>> oldFaces;
+ oldFaces.swap(m_faces);
+
+ ///\todo #3521 for each face needed under m_rules:
+ /// if it's in oldFaces, add to m_faces and remove from oldFaces;
+ /// otherwise, create via factory and add to m_faces
+
+ ///\todo #3521 close faces in oldFaces
+}
+
+NetdevBound::Rule
+NetdevBound::parseRule(int index, const ConfigSection& confRule) const
+{
+ Rule rule;
+
+ bool hasWhitelist = false;
+ bool hasBlacklist = false;
+ for (const auto& pair : confRule) {
+ const std::string& key = pair.first;
+ const ConfigSection& value = pair.second;
+ if (key == "remote") {
+ try {
+ rule.remotes.emplace_back(value.get_value<std::string>());
+ }
+ catch (const FaceUri::Error& ex) {
+ BOOST_THROW_EXCEPTION(RuleParseError(index, "invalid remote FaceUri", ex.what()));
+ }
+ if (!rule.remotes.back().isCanonical()) {
+ BOOST_THROW_EXCEPTION(RuleParseError(index, "remote FaceUri is not canonical"));
+ }
+ }
+ else if (key == "whitelist") {
+ if (hasWhitelist) {
+ BOOST_THROW_EXCEPTION(RuleParseError(index, "duplicate whitelist"));
+ }
+ try {
+ rule.netifPredicate.parseWhitelist(value);
+ }
+ catch (const ConfigFile::Error& ex) {
+ BOOST_THROW_EXCEPTION(RuleParseError(index, "invalid whitelist", ex.what()));
+ }
+ hasWhitelist = true;
+ }
+ else if (key == "blacklist") {
+ if (hasBlacklist) {
+ BOOST_THROW_EXCEPTION(RuleParseError(index, "duplicate blacklist"));
+ }
+ try {
+ rule.netifPredicate.parseBlacklist(value);
+ }
+ catch (const ConfigFile::Error& ex) {
+ BOOST_THROW_EXCEPTION(RuleParseError(index, "invalid blacklist", ex.what()));
+ }
+ hasBlacklist = true;
+ }
+ else {
+ BOOST_THROW_EXCEPTION(RuleParseError(index, "unrecognized option " + key));
+ }
+ }
+
+ if (rule.remotes.empty()) {
+ BOOST_THROW_EXCEPTION(RuleParseError(index, "remote FaceUri is missing"));
+ }
+
+ ///\todo #3521 for each remote, check that there is a factory providing scheme+dev scheme
+ return rule;
+}
+
+} // namespace face
+} // namespace nfd
diff --git a/daemon/face/netdev-bound.hpp b/daemon/face/netdev-bound.hpp
new file mode 100644
index 0000000..17a6ce8
--- /dev/null
+++ b/daemon/face/netdev-bound.hpp
@@ -0,0 +1,93 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2018, Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology,
+ * The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFD_DAEMON_FACE_NETDEV_BOUND_HPP
+#define NFD_DAEMON_FACE_NETDEV_BOUND_HPP
+
+#include "protocol-factory.hpp"
+
+namespace nfd {
+namespace face {
+
+class FaceSystem;
+
+/** \brief manages netdev-bound faces
+ */
+class NetdevBound : noncopyable
+{
+public:
+ class RuleParseError : public ConfigFile::Error
+ {
+ public:
+ RuleParseError(int index, std::string msg)
+ : Error("Error parsing face_system.netdev_bound.rule[" + to_string(index) + "]: " + msg)
+ , index(index)
+ , msg(std::move(msg))
+ {
+ }
+
+ RuleParseError(int index, std::string msg, const char* innerMsg)
+ : RuleParseError(index, msg + " - " + innerMsg)
+ {
+ }
+
+ public:
+ int index;
+ std::string msg;
+ };
+
+ NetdevBound(const ProtocolFactoryCtorParams& params, const FaceSystem& faceSystem);
+
+ /** \brief process face_system.netdev_bound config section
+ */
+ void
+ processConfig(OptionalConfigSection configSection,
+ FaceSystem::ConfigContext& context);
+
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+ struct Rule
+ {
+ std::vector<FaceUri> remotes;
+ NetworkInterfacePredicate netifPredicate;
+ };
+
+ Rule
+ parseRule(int index, const ConfigSection& confRule) const;
+
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+ const FaceSystem& m_faceSystem;
+ FaceCreatedCallback m_addFace;
+ shared_ptr<ndn::net::NetworkMonitor> m_netmon;
+
+ std::vector<Rule> m_rules;
+
+ using Key = std::pair<FaceUri, std::string>;
+ std::map<Key, shared_ptr<Face>> m_faces;
+};
+
+} // namespace face
+} // namespace nfd
+
+#endif // NFD_DAEMON_FACE_NETDEV_BOUND_HPP
diff --git a/daemon/face/protocol-factory.cpp b/daemon/face/protocol-factory.cpp
index 0a8a150..fb1440d 100644
--- a/daemon/face/protocol-factory.cpp
+++ b/daemon/face/protocol-factory.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2014-2017, Regents of the University of California,
+ * Copyright (c) 2014-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -66,5 +66,21 @@
BOOST_ASSERT(netmon != nullptr);
}
+shared_ptr<Face>
+ProtocolFactory::createNetdevBoundFace(const FaceUri& remote,
+ const shared_ptr<const ndn::net::NetworkInterface>& netif)
+{
+ BOOST_ASSERT(remote.isCanonical());
+ return this->doCreateNetdevBoundFace(remote, netif);
+}
+
+shared_ptr<Face>
+ProtocolFactory::doCreateNetdevBoundFace(const FaceUri& remote,
+ const shared_ptr<const ndn::net::NetworkInterface>& netif)
+{
+ BOOST_THROW_EXCEPTION(Error(
+ "this protocol factory does not support netdev-bound faces"));
+}
+
} // namespace face
} // namespace nfd
diff --git a/daemon/face/protocol-factory.hpp b/daemon/face/protocol-factory.hpp
index 74dbde7..f3d7807 100644
--- a/daemon/face/protocol-factory.hpp
+++ b/daemon/face/protocol-factory.hpp
@@ -156,6 +156,18 @@
virtual std::vector<shared_ptr<const Channel>>
getChannels() const = 0;
+ /** \brief Create a netdev-bound face
+ * \param remote remote FaceUri, must be canonical
+ * \param netdev local network interface
+ * \return new face
+ * \throw Error cannot create a face using specified arguments
+ * \note The caller must ensure there is no existing netdev-bound face with same remote FaceUri
+ * on the same local network interface.
+ */
+ shared_ptr<Face>
+ createNetdevBoundFace(const FaceUri& remote,
+ const shared_ptr<const ndn::net::NetworkInterface>& netdev);
+
protected:
explicit
ProtocolFactory(const CtorParams& params);
@@ -169,6 +181,26 @@
return channels;
}
+private:
+ /** \brief Create a netdev-bound face
+ * \sa createNetdevBoundFace
+ *
+ * The base class implementation always throws Error indicating netdev-bound faces are not
+ * supported.
+ *
+ * A subclass that offers netdev-bound faces should override this method, and also expose
+ * "scheme+dev" in providedSchemes. For example, UdpFactory should provide "udp4+dev" scheme,
+ * in addition to "udp4" scheme.
+ *
+ * The face should be constructed immediately. Face persistency shall be reported as PERMANENT.
+ * Face state shall remain DOWN until underlying transport is connected. The face shall remain
+ * open until after .close() is invoked, and survive all socket errors; in case the network
+ * interface disappears, the face shall remain DOWN until .close() is invoked.
+ */
+ virtual shared_ptr<Face>
+ doCreateNetdevBoundFace(const FaceUri& remote,
+ const shared_ptr<const ndn::net::NetworkInterface>& netif);
+
private: // registry
using CreateFunc = std::function<unique_ptr<ProtocolFactory>(const CtorParams&)>;
using Registry = std::map<std::string, CreateFunc>; // indexed by factory id
diff --git a/nfd.conf.sample.in b/nfd.conf.sample.in
index c015eb0..eec2bfc 100644
--- a/nfd.conf.sample.in
+++ b/nfd.conf.sample.in
@@ -230,6 +230,37 @@
@IF_HAVE_WEBSOCKET@ enable_v4 yes ; set to 'no' to disable listening on IPv4 socket, default 'yes'
@IF_HAVE_WEBSOCKET@ enable_v6 yes ; set to 'no' to disable listening on IPv6 socket, default 'yes'
@IF_HAVE_WEBSOCKET@}
+
+ ; The netdev_bound section defines faces bound to netdevices.
+ netdev_bound
+ {
+ ; A rule consists of a whitelist, a blacklist, and a set of remote FaceUris, and will cause the
+ ; creation of zero or more faces bound to netdevices. One face will be created per accepted
+ ; netdev per remote. There can be any number of rules in the netdev_bound section.
+
+ ; rule
+ ; {
+ ; ; Remote FaceUri to which the netdev-bound faces will connect.
+ ; ; Rule can contain multiple remotes. One face will be created for each remote.
+ ; ; All FaceUris must be in canonical form. Currently only udp4 and udp6 are supported.
+ ; remote udp4://192.0.2.1:6363
+ ;
+ ; ; Whitelist and blacklist can contain, in no particular order:
+ ; ; - interface names, including wildcard patterns (e.g., 'ifname eth0', 'ifname en*', 'ifname wlp?s0')
+ ; ; - MAC addresses (e.g., 'ether 85:3b:4d:d3:5f:c2')
+ ; ; - IPv4 subnets (e.g., 'subnet 192.0.2.0/24')
+ ; ; - IPv6 subnets (e.g., 'subnet 2001:db8::/32')
+ ; ; - a single asterisk ('*') that matches all interfaces
+ ; ; By default, all interfaces are whitelisted.
+ ; whitelist
+ ; {
+ ; *
+ ; }
+ ; blacklist
+ ; {
+ ; }
+ ; }
+ }
}
; The authorizations section grants privileges to authorized keys.
diff --git a/tests/daemon/face/face-system-fixture.hpp b/tests/daemon/face/face-system-fixture.hpp
index 1d69179..b3ae91f 100644
--- a/tests/daemon/face/face-system-fixture.hpp
+++ b/tests/daemon/face/face-system-fixture.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2014-2017, Regents of the University of California,
+ * Copyright (c) 2014-2018, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -47,6 +47,7 @@
FaceSystemFixture()
: netmon(make_shared<ndn::net::NetworkMonitorStub>(~0))
, faceSystem(faceTable, netmon)
+ , netdevBound(*faceSystem.m_netdevBound)
{
faceSystem.setConfigFile(configFile);
}
@@ -137,6 +138,7 @@
FaceTable faceTable;
shared_ptr<ndn::net::NetworkMonitorStub> netmon;
FaceSystem faceSystem;
+ NetdevBound& netdevBound;
};
/** \brief FaceSystemFixture with a ProtocolFactory reference
@@ -154,6 +156,54 @@
FactoryType& factory;
};
+/** \brief A dummy ProtocolFactory for testing FaceSystem configuration parsing.
+ */
+class DummyProtocolFactory : public ProtocolFactory
+{
+public:
+ DummyProtocolFactory(const CtorParams& params)
+ : ProtocolFactory(params)
+ {
+ }
+
+ void
+ processConfig(OptionalConfigSection configSection,
+ FaceSystem::ConfigContext& context) final
+ {
+ processConfigHistory.push_back({configSection, context.isDryRun,
+ context.generalConfig.wantCongestionMarking});
+ if (!context.isDryRun) {
+ this->providedSchemes = this->newProvidedSchemes;
+ }
+ }
+
+ void
+ createFace(const CreateFaceRequest& req,
+ const FaceCreatedCallback& onCreated,
+ const FaceCreationFailedCallback& onFailure) final
+ {
+ BOOST_FAIL("createFace should not be called");
+ }
+
+ std::vector<shared_ptr<const Channel>>
+ getChannels() const final
+ {
+ BOOST_FAIL("getChannels should not be called");
+ return {};
+ }
+
+public:
+ struct ProcessConfigArgs
+ {
+ OptionalConfigSection configSection;
+ bool isDryRun;
+ bool wantCongestionMarking;
+ };
+ std::vector<ProcessConfigArgs> processConfigHistory;
+
+ std::set<std::string> newProvidedSchemes;
+};
+
} // namespace tests
} // namespace face
} // namespace nfd
diff --git a/tests/daemon/face/face-system.t.cpp b/tests/daemon/face/face-system.t.cpp
index b22979a..a7be4c8 100644
--- a/tests/daemon/face/face-system.t.cpp
+++ b/tests/daemon/face/face-system.t.cpp
@@ -37,52 +37,6 @@
BOOST_AUTO_TEST_SUITE(ProcessConfig)
-class DummyProtocolFactory : public ProtocolFactory
-{
-public:
- DummyProtocolFactory(const CtorParams& params)
- : ProtocolFactory(params)
- {
- }
-
- void
- processConfig(OptionalConfigSection configSection,
- FaceSystem::ConfigContext& context) final
- {
- processConfigHistory.push_back({configSection, context.isDryRun,
- context.generalConfig.wantCongestionMarking});
- if (!context.isDryRun) {
- this->providedSchemes = this->newProvidedSchemes;
- }
- }
-
- void
- createFace(const CreateFaceRequest& req,
- const FaceCreatedCallback& onCreated,
- const FaceCreationFailedCallback& onFailure) final
- {
- BOOST_FAIL("createFace should not be called");
- }
-
- std::vector<shared_ptr<const Channel>>
- getChannels() const final
- {
- BOOST_FAIL("getChannels should not be called");
- return {};
- }
-
-public:
- struct ProcessConfigArgs
- {
- OptionalConfigSection configSection;
- bool isDryRun;
- bool wantCongestionMarking;
- };
- std::vector<ProcessConfigArgs> processConfigHistory;
-
- std::set<std::string> newProvidedSchemes;
-};
-
BOOST_AUTO_TEST_CASE(Normal)
{
faceSystem.m_factories["f1"] = make_unique<DummyProtocolFactory>(faceSystem.makePFCtorParams());
@@ -208,7 +162,7 @@
BOOST_AUTO_TEST_SUITE_END() // ProcessConfig
BOOST_AUTO_TEST_SUITE_END() // TestFaceSystem
-BOOST_AUTO_TEST_SUITE_END() // Mgmt
+BOOST_AUTO_TEST_SUITE_END() // Face
} // namespace tests
} // namespace face
diff --git a/tests/daemon/face/netdev-bound.t.cpp b/tests/daemon/face/netdev-bound.t.cpp
new file mode 100644
index 0000000..9f71fc1
--- /dev/null
+++ b/tests/daemon/face/netdev-bound.t.cpp
@@ -0,0 +1,116 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2018, Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology,
+ * The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "face/netdev-bound.hpp"
+#include "face-system-fixture.hpp"
+
+#include "tests/test-common.hpp"
+
+namespace nfd {
+namespace face {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Face)
+BOOST_FIXTURE_TEST_SUITE(TestNetdevBound, FaceSystemFixture)
+
+BOOST_AUTO_TEST_SUITE(ProcessConfig)
+
+BOOST_AUTO_TEST_CASE(Normal)
+{
+ faceSystem.m_factories["pf"] = make_unique<DummyProtocolFactory>(faceSystem.makePFCtorParams());
+ auto pf = static_cast<DummyProtocolFactory*>(faceSystem.getFactoryById("pf"));
+ pf->newProvidedSchemes.insert("udp4+dev");
+
+ const std::string CONFIG = R"CONFIG(
+ face_system
+ {
+ pf
+ {
+ }
+ netdev_bound
+ {
+ rule
+ {
+ remote udp4://192.0.2.1:6363
+ remote udp4://192.0.2.2:6363
+ whitelist
+ {
+ *
+ }
+ blacklist
+ {
+ ifname wlan0
+ }
+ }
+ rule
+ {
+ remote udp4://192.0.2.3:6363
+ remote udp4://192.0.2.4:6363
+ whitelist
+ {
+ ifname eth0
+ }
+ blacklist
+ {
+ }
+ }
+ rule
+ {
+ remote udp4://192.0.2.5:6363
+ }
+ }
+ }
+ )CONFIG";
+
+ parseConfig(CONFIG, true);
+ parseConfig(CONFIG, false);
+}
+
+BOOST_AUTO_TEST_CASE(NonCanonicalRemote)
+{
+ const std::string CONFIG = R"CONFIG(
+ face_system
+ {
+ netdev_bound
+ {
+ rule
+ {
+ remote udp://192.0.2.1
+ }
+ }
+ }
+ )CONFIG";
+
+ BOOST_CHECK_THROW(parseConfig(CONFIG, true), ConfigFile::Error);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // ProcessConfig
+
+BOOST_AUTO_TEST_SUITE_END() // TestNetdevBound
+BOOST_AUTO_TEST_SUITE_END() // Face
+
+} // namespace tests
+} // namespace face
+} // namespace nfd