]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#628,!341] Shared network parser supports interface-id.
authorMarcin Siodelski <marcin@isc.org>
Mon, 27 May 2019 13:13:21 +0000 (15:13 +0200)
committerMarcin Siodelski <marcin@isc.org>
Mon, 27 May 2019 14:25:50 +0000 (10:25 -0400)
src/lib/dhcpsrv/parsers/shared_network_parser.cc
src/lib/dhcpsrv/tests/shared_network_parser_unittest.cc

index 15fd80d91245ce825dfa0a3576279ad17e9e098f..6572b0555984863539d14a3ad14ecb8322b9e687 100644 (file)
@@ -19,6 +19,7 @@
 
 using namespace isc::asiolink;
 using namespace isc::data;
+using namespace isc::util;
 
 namespace isc {
 namespace dhcp {
@@ -205,6 +206,45 @@ SharedNetwork6Parser::parse(const data::ConstElementPtr& shared_network_data) {
                                                     "preferred-lifetime"));
         }
 
+        // Get interface-id option content. For now we support string
+        // representation only
+        Optional<std::string> ifaceid;
+        if (shared_network_data->contains("interface-id")) {
+            ifaceid = getString(shared_network_data, "interface-id");
+        }
+
+        Optional<std::string> iface;
+        if (shared_network_data->contains("interface")) {
+            iface = getString(shared_network_data, "interface");
+        }
+
+        // Specifying both interface for locally reachable subnets and
+        // interface id for relays is mutually exclusive. Need to test for
+        // this condition.
+        if (!ifaceid.unspecified() && !iface.unspecified() && !ifaceid.empty() &&
+            !iface.empty()) {
+            isc_throw(isc::dhcp::DhcpConfigError,
+                      "parser error: interface (defined for locally reachable "
+                      "subnets) and interface-id (defined for subnets reachable"
+                      " via relays) cannot be defined at the same time for "
+                      "shared network " << name << "("
+                      << shared_network_data->getPosition() << ")");
+        }
+
+        // Configure interface-id for remote interfaces, if defined
+        if (!ifaceid.unspecified() && !ifaceid.empty()) {
+            std::string ifaceid_value = ifaceid.get();
+            OptionBuffer tmp(ifaceid_value.begin(), ifaceid_value.end());
+            OptionPtr opt(new Option(Option::V6, D6O_INTERFACE_ID, tmp));
+            shared_network->setInterfaceId(opt);
+        }
+
+        // Get interface name. If it is defined, then the subnet is available
+        // directly over specified network interface.
+        if (!iface.unspecified() && !iface.empty()) {
+            shared_network->setIface(iface);
+        }
+
         // Interface is an optional parameter
         if (shared_network_data->contains("interface")) {
             shared_network->setIface(getString(shared_network_data, "interface"));
index 9b04036a6b380c43bc8a9a81208c66be00889b2d..9c007727adeb87e668c9c4927a333e078d355f66 100644 (file)
@@ -220,7 +220,7 @@ TEST_F(SharedNetwork4ParserTest, parse) {
     SharedNetwork4Parser parser;
     SharedNetwork4Ptr network;
 
-    try { 
+    try {
         network = parser.parse(config_element);
     } catch (const std::exception& ex) {
         std::cout << "kabook: " << ex.what() << std::endl;
@@ -407,13 +407,19 @@ TEST_F(SharedNetwork4ParserTest, relayInfoTests) {
 class SharedNetwork6ParserTest : public SharedNetworkParserTest {
 public:
 
+    /// @brief Constructor.
+    SharedNetwork6ParserTest()
+        : SharedNetworkParserTest(), network_(), use_iface_id_(false) {
+    }
+
     /// @brief Creates valid shared network configuration.
     ///
     /// @return Valid shared network configuration.
     virtual std::string getWorkingConfig() const {
             std::string config = "{"
                 "    \"client-class\": \"srv1\","
-                "    \"interface\": \"eth1\","
+                + std::string(use_iface_id_ ? "\"interface-id\": " : "\"interface\": ") +
+                "\"eth1\","
                 "    \"name\": \"bird\","
                 "    \"preferred-lifetime\": 211,"
                 "    \"rapid-commit\": true,"
@@ -479,8 +485,13 @@ public:
         return (*network_);
     }
 
-private:
+public:
+
     SharedNetwork6Ptr network_;
+
+    /// Boolean flag indicating if the interface-id should be used instead
+    /// of interface.
+    bool use_iface_id_;
 };
 
 // This test verifies that shared network parser for IPv4 works properly
@@ -550,6 +561,41 @@ TEST_F(SharedNetwork6ParserTest, parse) {
     EXPECT_EQ("2001:db8:1::cafe", addresses[0].toText());
 }
 
+// This test verifies that shared network parser for IPv4 works properly
+// in a positive test scenario.
+TEST_F(SharedNetwork6ParserTest, parseWithInterfaceId) {
+    // Use the configuration with interface-id instead of interface parameter.
+    use_iface_id_ = true;
+    std::string config = getWorkingConfig();
+    ElementPtr config_element = Element::fromJSON(config);
+
+    // Parse configuration specified above.
+    SharedNetwork6Parser parser;
+    SharedNetwork6Ptr network;
+    ASSERT_NO_THROW(network = parser.parse(config_element));
+    ASSERT_TRUE(network);
+
+    // Check that interface-id has been parsed.
+    auto opt_iface_id = network->getInterfaceId();
+    ASSERT_TRUE(opt_iface_id);
+}
+
+// This test verifies that error is returned when trying to configure a
+// shared network with both interface and interface id.
+TEST_F(SharedNetwork6ParserTest, mutuallyExclusiveInterfaceId) {
+    // Use the configuration with interface-id instead of interface parameter.
+    use_iface_id_ = true;
+    std::string config = getWorkingConfig();
+    ElementPtr config_element = Element::fromJSON(config);
+
+    // Add interface which is mutually exclusive with interface-id
+    config_element->set("interface", Element::create("eth1"));
+
+    // Parse configuration specified above.
+    SharedNetwork6Parser parser;
+    EXPECT_THROW(parser.parse(config_element), DhcpConfigError);
+}
+
 // This test verifies that it's possible to specify client-class
 // on shared-network level.
 TEST_F(SharedNetwork6ParserTest, clientClass) {