]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[3246] Implemented unit test which checks collisions of prefixes.
authorMarcin Siodelski <marcin@isc.org>
Tue, 20 May 2014 11:23:20 +0000 (13:23 +0200)
committerMarcin Siodelski <marcin@isc.org>
Tue, 20 May 2014 11:23:20 +0000 (13:23 +0200)
src/bin/dhcp6/tests/Makefile.am
src/bin/dhcp6/tests/dhcp6_client.cc
src/bin/dhcp6/tests/dhcp6_client.h
src/bin/dhcp6/tests/dhcp6_test_utils.cc
src/bin/dhcp6/tests/dhcp6_test_utils.h
src/bin/dhcp6/tests/rebind_unittest.cc
src/bin/dhcp6/tests/sarr_unittest.cc [new file with mode: 0644]

index 424bd5b29bdc7a920db40343f0a9bc50dd8cd80c..754da78d57be73598f67f4c95ed631f3a0cf73d3 100644 (file)
@@ -86,6 +86,7 @@ dhcp6_unittests_SOURCES += ../config_parser.cc ../config_parser.h
 dhcp6_unittests_SOURCES += wireshark.cc
 dhcp6_unittests_SOURCES += dhcp6_client.cc dhcp6_client.h
 dhcp6_unittests_SOURCES += rebind_unittest.cc
+dhcp6_unittests_SOURCES += sarr_unittest.cc
 
 nodist_dhcp6_unittests_SOURCES  = ../dhcp6_messages.h ../dhcp6_messages.cc
 nodist_dhcp6_unittests_SOURCES += marker_file.h test_libraries.h
index c1bad42d40c0b4ed8349f86e45c33d2b095ec860..5636e9e4eb59b4cb84edf6904be61c99094a74e3 100644 (file)
@@ -39,7 +39,8 @@ Dhcp6Client::Dhcp6Client() :
     srv_(boost::shared_ptr<NakedDhcpv6Srv>(new NakedDhcpv6Srv(0))),
     use_na_(false),
     use_pd_(false),
-    use_relay_(false) {
+    use_relay_(false),
+    prefix_hint_() {
 }
 
 Dhcp6Client::Dhcp6Client(boost::shared_ptr<NakedDhcpv6Srv>& srv) :
@@ -234,8 +235,11 @@ Dhcp6Client::doSolicit() {
                                                               1234)));
     }
     if (use_pd_) {
-        context_.query_->addOption(Option6IAPtr(new Option6IA(D6O_IA_PD,
-                                                              5678)));
+        Option6IAPtr ia(new Option6IA(D6O_IA_PD, 5678));
+        if (prefix_hint_) {
+            ia->addOption(prefix_hint_);
+        }
+        context_.query_->addOption(ia);
     }
     sendMsg(context_.query_);
     context_.response_ = receiveOneMsg();
@@ -358,6 +362,14 @@ Dhcp6Client::sendMsg(const Pkt6Ptr& msg) {
     srv_->run();
 }
 
+void
+Dhcp6Client::useHint(const uint32_t pref_lft, const uint32_t valid_lft,
+                     const uint8_t len, const std::string& prefix) {
+    prefix_hint_.reset(new Option6IAPrefix(D6O_IAPREFIX,
+                                           asiolink::IOAddress(prefix),
+                                           len, pref_lft, valid_lft));
+}
+
 
 } // end of namespace isc::dhcp::test
 } // end of namespace isc::dhcp
index 3ccf091b1fe16d9cc02f8dfe6fb9f467e720d9a1..47b2e6d0c1cb1321e03da71e428f24ecbb49f027 100644 (file)
@@ -26,7 +26,6 @@ namespace isc {
 namespace dhcp {
 namespace test {
 
-
 /// @brief DHCPv6 client used for unit testing.
 ///
 /// This class implements a DHCPv6 "client" which interoperates with the
@@ -76,6 +75,11 @@ public:
     /// Currently it simply contains the collection of leases acquired.
     struct Configuration {
         std::vector<LeaseInfo> leases_;
+
+        /// @brief Clears configuration.
+        void clear() {
+            leases_.clear();
+        }
     };
 
     /// @brief Holds the DHCPv6 messages taking part in transaction between
@@ -175,6 +179,13 @@ public:
     /// @todo Perform sanity checks on returned messages.
     void doRequest();
 
+    /// @brief Removes the stateful configuration obtained from the server.
+    ///
+    /// It removes all leases held by the client.
+    void clearConfig() {
+        config_.clear();
+    }
+
     /// @brief Simulates aging of leases by the specified number of seconds.
     ///
     /// This function moves back the time of acquired leases by the specified
@@ -250,6 +261,15 @@ public:
         dest_addr_ = dest_addr;
     }
 
+    /// @brief Sets a prefix hint to be sent to a server.
+    ///
+    /// @param pref_lft Preferred lifetime.
+    /// @param valid_lft Valid lifetime.
+    /// @param len Prefix length.
+    /// @param prefix Prefix for which the client has a preference.
+    void useHint(const uint32_t pref_lft, const uint32_t valid_lft,
+                 const uint8_t len, const std::string& prefix);
+
     /// @brief Place IA_NA options to request address assignment.
     ///
     /// This function configures the client to place IA_NA options in its
@@ -383,6 +403,9 @@ private:
     bool use_na_;    ///< Enable address assignment.
     bool use_pd_;    ///< Enable prefix delegation.
     bool use_relay_; ///< Enable relaying messages to the server.
+
+    /// @brief Pointer to the option holding a prefix hint.
+    Option6IAPrefixPtr prefix_hint_;
 };
 
 } // end of namespace isc::dhcp::test
index 9207d4dbf749cc6d7f10f8d2ef67c0addd81c761..88397111a07b897e1b07c236ede95192de307274 100644 (file)
@@ -590,18 +590,22 @@ Dhcpv6SrvTest::testReleaseReject(Lease::Type type, const IOAddress& addr) {
 
 void
 Dhcpv6SrvTest::configure(const std::string& config) {
+    configure(config, srv_);
+}
+
+void
+Dhcpv6SrvTest::configure(const std::string& config, NakedDhcpv6Srv& srv) {
     ElementPtr json = data::Element::fromJSON(config);
     ConstElementPtr status;
 
     // Configure the server and make sure the config is accepted
-    EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
+    EXPECT_NO_THROW(status = configureDhcp6Server(srv, json));
     ASSERT_TRUE(status);
     int rcode;
     ConstElementPtr comment = config::parseAnswer(rcode, status);
     ASSERT_EQ(0, rcode);
 }
 
-
 // Generate IA_NA option with specified parameters
 boost::shared_ptr<Option6IA>
 NakedDhcpv6SrvTest::generateIA(uint16_t type, uint32_t iaid, uint32_t t1,
index 90ed4bc8f34a281a66b616da84d644641d344e7c..27e053992a2bfbfd8636c07667ab7dfe33b2ed9b 100644 (file)
@@ -354,8 +354,13 @@ public:
     /// @brief Runs DHCPv6 configuration from the JSON string.
     ///
     /// @param config String holding server configuration in JSON format.
-    void
-    configure(const std::string& config);
+    void configure(const std::string& config);
+
+    /// @brief Configure the DHCPv6 server using the JSON string.
+    ///
+    /// @param config String holding server configuration in JSON format.
+    /// @param srv Server to be configured.
+    void configure(const std::string& config, NakedDhcpv6Srv& srv);
 
     /// @brief Checks that server response (ADVERTISE or REPLY) contains proper
     ///        IA_NA option
index 2de10d1b4ff487449ad2ac2934d8f24a328115e6..33424010b440ffa58941df1e4684d6e6135cbe5b 100644 (file)
@@ -208,12 +208,6 @@ public:
           iface_mgr_test_config_(true) {
     }
 
-    /// @brief Configure the DHCPv6 server using the JSON string.
-    ///
-    /// @param config New configuration in JSON format.
-    /// @param srv Server to be configured.
-    void configure(const std::string& config, NakedDhcpv6Srv& srv);
-
     /// @brief Make 4-way exchange to obtain a lease.
     ///
     /// @param config_index Index of the configuration held in @c REBIND_CONFIGS
@@ -229,19 +223,6 @@ public:
 
 };
 
-void
-RebindTest::configure(const std::string& config, NakedDhcpv6Srv& srv) {
-    ElementPtr json = Element::fromJSON(config);
-    ConstElementPtr status;
-
-    // Configure the server and make sure the config is accepted
-    EXPECT_NO_THROW(status = configureDhcp6Server(srv, json));
-    ASSERT_TRUE(status);
-    int rcode;
-    ConstElementPtr comment = config::parseAnswer(rcode, status);
-    ASSERT_EQ(0, rcode);
-}
-
 void
 RebindTest::requestLease(const int config_index, const int subnets_num,
                          Dhcp6Client& client) {
diff --git a/src/bin/dhcp6/tests/sarr_unittest.cc b/src/bin/dhcp6/tests/sarr_unittest.cc
new file mode 100644 (file)
index 0000000..00c9d50
--- /dev/null
@@ -0,0 +1,124 @@
+// Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <dhcp/tests/iface_mgr_test_config.h>
+#include <dhcp6/tests/dhcp6_test_utils.h>
+#include <dhcp6/tests/dhcp6_client.h>
+
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::dhcp::test;
+using namespace isc::test;
+
+namespace {
+
+/// @brief Set of JSON configurations used by the SARR unit tests.
+///
+/// - Configuration 0:
+///   - one subnet used on eth0 interface
+///   - prefixes of length 64, delegated from the pool: 2001:db8:3::/48
+const char* CONFIGS[] = {
+    // Configuration 0
+    "{ \"interfaces\": [ \"all\" ],"
+        "\"preferred-lifetime\": 3000,"
+        "\"rebind-timer\": 2000, "
+        "\"renew-timer\": 1000, "
+        "\"subnet6\": [ { "
+        "    \"pd-pools\": ["
+        "        { \"prefix\": \"2001:db8:3::\", "
+        "          \"prefix-len\": 48, "
+        "          \"delegated-len\": 64"
+        "        } ],"
+        "    \"subnet\": \"2001:db8::/32\", "
+        "    \"interface-id\": \"\","
+        "    \"interface\": \"eth0\""
+        " } ],"
+        "\"valid-lifetime\": 4000 }"
+};
+
+/// @brief Test fixture class for testing 4-way exchange: Solicit-Advertise,
+/// Request-Reply.
+class SARRTest : public Dhcpv6SrvTest {
+public:
+    /// @brief Constructor.
+    ///
+    /// Sets up fake interfaces.
+    SARRTest()
+        : Dhcpv6SrvTest(),
+          iface_mgr_test_config_(true) {
+    }
+
+    /// @brief Interface Manager's fake configuration control.
+    IfaceMgrTestConfig iface_mgr_test_config_;
+};
+
+/// Check that server processes correctly a prefix hint sent by the client.
+/// This test checks that the server doesn't allocate colliding prefixes
+/// as a result of receiving hints from two clients which set the
+/// non-significant bytes of the prefix in their hints. The server should zero
+/// the non-significant bytes of the hint and allocate the prefix of the
+/// correct (configured) length.
+TEST_F(SARRTest, directClientPrefixHint) {
+    Dhcp6Client client;
+    // Configure client to request IA_PD.
+    client.usePD();
+    configure(CONFIGS[0], *client.getServer());
+    // Make sure we ended-up having expected number of subnets configured.
+    const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
+    ASSERT_EQ(1, subnets->size());
+    // Append IAPREFIX option to the client's message.
+    ASSERT_NO_THROW(client.useHint(100, 200, 56, "2001:db8:3:33::33"));
+    // Perform 4-way exchange.
+    ASSERT_NO_THROW(client.doSARR());
+    // Server should have assigned a prefix.
+    ASSERT_EQ(1, client.getLeaseNum());
+    Lease6 lease_client = client.getLease(0);
+    // The server should correctly deal with the least significant bytes
+    // of the hint being set. It should set them to zero and use the
+    // valid portion of the hint.
+    EXPECT_EQ("2001:db8:3:33::", lease_client.addr_.toText());
+    // Server ignores other parts of the IAPREFIX option.
+    EXPECT_EQ(64, lease_client.prefixlen_);
+    EXPECT_EQ(3000, lease_client.preferred_lft_);
+    EXPECT_EQ(4000, lease_client.valid_lft_);
+    Lease6Ptr lease_server = checkLease(lease_client);
+    // Check that the server recorded the lease.
+    ASSERT_TRUE(lease_server);
+
+    // Remove existing lease and modify the DUID of the client to simulate
+    // the case that different client is trying to get the prefix.
+    client.clearConfig();
+    client.modifyDUID();
+
+    // Use the hint with some least significant bytes set.
+    ASSERT_NO_THROW(client.useHint(100, 200, 56, "2001:db8:3:33::34"));
+    ASSERT_NO_THROW(client.doSARR());
+    // Server should assign a lease.
+    ASSERT_EQ(1, client.getLeaseNum());
+    lease_client = client.getLease(0);
+    // The hint collides with the existing lease, so the server should not
+    // assign for the second client.
+    EXPECT_NE("2001:db8:3:33::", lease_client.addr_.toText());
+    EXPECT_NE("2001:db8:3:33::34", lease_client.addr_.toText());
+    // Check that the assigned prefix belongs to the pool.
+    (*subnets)[0]->inPool(Lease::TYPE_PD, lease_client.addr_);
+    EXPECT_EQ(64, lease_client.prefixlen_);
+    EXPECT_EQ(3000, lease_client.preferred_lft_);
+    EXPECT_EQ(4000, lease_client.valid_lft_);
+    lease_server = checkLease(lease_client);
+    ASSERT_TRUE(lease_server);
+}
+
+} // end of anonymous namespace