Browse Source

[3246] Implemented unit test which checks collisions of prefixes.

Marcin Siodelski 11 years ago
parent
commit
34ce8a68fd

+ 1 - 0
src/bin/dhcp6/tests/Makefile.am

@@ -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

+ 15 - 3
src/bin/dhcp6/tests/dhcp6_client.cc

@@ -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

+ 24 - 1
src/bin/dhcp6/tests/dhcp6_client.h

@@ -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

+ 6 - 2
src/bin/dhcp6/tests/dhcp6_test_utils.cc

@@ -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,

+ 7 - 2
src/bin/dhcp6/tests/dhcp6_test_utils.h

@@ -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

+ 0 - 19
src/bin/dhcp6/tests/rebind_unittest.cc

@@ -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
@@ -230,19 +224,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) {
     // Check that the index is in the configuration table.

+ 124 - 0
src/bin/dhcp6/tests/sarr_unittest.cc

@@ -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