From: Marcin Siodelski Date: Tue, 20 May 2014 11:23:20 +0000 (+0200) Subject: [3246] Implemented unit test which checks collisions of prefixes. X-Git-Tag: trac3434_base~26^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=34ce8a68fd0efcef6e81b7fd563cea4774867745;p=thirdparty%2Fkea.git [3246] Implemented unit test which checks collisions of prefixes. --- diff --git a/src/bin/dhcp6/tests/Makefile.am b/src/bin/dhcp6/tests/Makefile.am index 424bd5b29b..754da78d57 100644 --- a/src/bin/dhcp6/tests/Makefile.am +++ b/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 diff --git a/src/bin/dhcp6/tests/dhcp6_client.cc b/src/bin/dhcp6/tests/dhcp6_client.cc index c1bad42d40..5636e9e4eb 100644 --- a/src/bin/dhcp6/tests/dhcp6_client.cc +++ b/src/bin/dhcp6/tests/dhcp6_client.cc @@ -39,7 +39,8 @@ Dhcp6Client::Dhcp6Client() : srv_(boost::shared_ptr(new NakedDhcpv6Srv(0))), use_na_(false), use_pd_(false), - use_relay_(false) { + use_relay_(false), + prefix_hint_() { } Dhcp6Client::Dhcp6Client(boost::shared_ptr& 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 diff --git a/src/bin/dhcp6/tests/dhcp6_client.h b/src/bin/dhcp6/tests/dhcp6_client.h index 3ccf091b1f..47b2e6d0c1 100644 --- a/src/bin/dhcp6/tests/dhcp6_client.h +++ b/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 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 diff --git a/src/bin/dhcp6/tests/dhcp6_test_utils.cc b/src/bin/dhcp6/tests/dhcp6_test_utils.cc index 9207d4dbf7..88397111a0 100644 --- a/src/bin/dhcp6/tests/dhcp6_test_utils.cc +++ b/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 NakedDhcpv6SrvTest::generateIA(uint16_t type, uint32_t iaid, uint32_t t1, diff --git a/src/bin/dhcp6/tests/dhcp6_test_utils.h b/src/bin/dhcp6/tests/dhcp6_test_utils.h index 90ed4bc8f3..27e053992a 100644 --- a/src/bin/dhcp6/tests/dhcp6_test_utils.h +++ b/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 diff --git a/src/bin/dhcp6/tests/rebind_unittest.cc b/src/bin/dhcp6/tests/rebind_unittest.cc index 2de10d1b4f..33424010b4 100644 --- a/src/bin/dhcp6/tests/rebind_unittest.cc +++ b/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 @@ -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 index 0000000000..00c9d50fd8 --- /dev/null +++ b/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 +#include +#include +#include + +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