From: Razvan Becheriu Date: Fri, 5 Jun 2020 16:41:34 +0000 (+0300) Subject: [#1256] added unittests and addressed comments X-Git-Tag: Kea-1.7.9~87 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7aef490ffde94698e7c8a72e86195d1ff3067923;p=thirdparty%2Fkea.git [#1256] added unittests and addressed comments --- diff --git a/src/lib/dhcpsrv/subnet.cc b/src/lib/dhcpsrv/subnet.cc index 7a54538f38..0a1bf5dedc 100644 --- a/src/lib/dhcpsrv/subnet.cc +++ b/src/lib/dhcpsrv/subnet.cc @@ -12,8 +12,10 @@ #include #include #include + #include #include + #include #include @@ -64,7 +66,7 @@ Subnet::Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len, last_allocated_time_(), iface_(), shared_network_name_(), - mutex_() { + mutex_(boost::make_shared()) { if ((prefix.isV6() && len > 128) || (prefix.isV4() && len > 32)) { isc_throw(BadValue, @@ -76,8 +78,6 @@ Subnet::Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len, last_allocated_time_[Lease::TYPE_NA] = boost::posix_time::neg_infin; last_allocated_time_[Lease::TYPE_TA] = boost::posix_time::neg_infin; last_allocated_time_[Lease::TYPE_PD] = boost::posix_time::neg_infin; - - mutex_.reset(new std::mutex); } bool diff --git a/src/lib/dhcpsrv/subnet.h b/src/lib/dhcpsrv/subnet.h index 94f4d17a03..e2ac1b3648 100644 --- a/src/lib/dhcpsrv/subnet.h +++ b/src/lib/dhcpsrv/subnet.h @@ -36,10 +36,14 @@ namespace dhcp { class Subnet : public virtual Network { public: - /// @brief checks if specified address is in range + /// @brief checks if specified address is in range. + /// + /// @param addr this address will be checked if it is included in a specific + /// range + /// @return true if address is in range, false otherwise bool inRange(const isc::asiolink::IOAddress& addr) const; - /// @brief checks if the specified address is in pools + /// @brief checks if the specified address is in pools. /// /// Note the difference between inRange() and inPool() for addresses /// (i.e. *not* prefixes). For a given subnet (e.g. 2001::/64) there @@ -55,7 +59,7 @@ public: /// @return true if the address is in any of the pools bool inPool(Lease::Type type, const isc::asiolink::IOAddress& addr) const; - /// @brief checks if the specified address is in allowed pools + /// @brief checks if the specified address is in allowed pools. /// /// This takes also into account client classes /// @@ -68,7 +72,7 @@ public: const isc::asiolink::IOAddress& addr, const ClientClasses& client_classes) const; - /// @brief returns the last address that was tried from this subnet + /// @brief returns the last address that was tried from this subnet. /// /// This method returns the last address that was attempted to be allocated /// from this subnet. This is used as helper information for the next @@ -94,9 +98,10 @@ public: /// @return Time when a lease of a specified type has been allocated from /// this subnet. The negative infinity time is returned if a lease type is /// not recognized (which is unlikely). - boost::posix_time::ptime getLastAllocatedTime(const Lease::Type& lease_type) const; + boost::posix_time::ptime + getLastAllocatedTime(const Lease::Type& lease_type) const; - /// @brief sets the last address that was tried from this subnet + /// @brief sets the last address that was tried from this subnet. /// /// This method sets the last address that was attempted to be allocated /// from this subnet. This is used as helper information for the next @@ -111,11 +116,12 @@ public: void setLastAllocated(Lease::Type type, const isc::asiolink::IOAddress& addr); - /// @brief Returns unique ID for that subnet + /// @brief Returns unique ID for that subnet. + /// /// @return unique ID for that subnet SubnetID getID() const { return (id_); } - /// @brief Returns subnet parameters (prefix and prefix length) + /// @brief Returns subnet parameters (prefix and prefix length). /// /// @return (prefix, prefix length) pair std::pair get() const { @@ -146,13 +152,14 @@ public: /// within the subnet. void addPool(const PoolPtr& pool); - /// @brief Deletes all pools of specified type + /// @brief Deletes all pools of specified type. /// /// This method is used for testing purposes only + /// /// @param type type of pools to be deleted void delPools(Lease::Type type); - /// @brief Returns a pool that specified address belongs to + /// @brief Returns a pool that specified address belongs to. /// /// This method uses binary search to retrieve the pool. Thus, the number /// of comparisons performed by this method is logarithmic in the number @@ -173,9 +180,9 @@ public: const PoolPtr getPool(Lease::Type type, const isc::asiolink::IOAddress& addr, bool anypool = true) const; - /// @brief Returns a pool that specified address belongs to with classes + /// @brief Returns a pool that specified address belongs to with classes. /// - /// Variant using only pools allowing given classes + /// Variant using only pools allowing given classes. /// /// @param type pool type that the pool is looked for /// @param client_classes client class list which must be allowed @@ -184,7 +191,7 @@ public: const ClientClasses& client_classes, const isc::asiolink::IOAddress& addr) const; - /// @brief Returns a pool without any address specified + /// @brief Returns a pool without any address specified. /// /// @param type pool type that the pool is looked for /// @return returns one of the pools defined @@ -192,13 +199,13 @@ public: return (getPool(type, default_pool())); } - /// @brief Returns the default address that will be used for pool selection + /// @brief Returns the default address that will be used for pool selection. /// /// It must be implemented in derived classes (should return :: for Subnet6 - /// and 0.0.0.0 for Subnet4) + /// and 0.0.0.0 for Subnet4). virtual isc::asiolink::IOAddress default_pool() const = 0; - /// @brief Returns all pools (const variant) + /// @brief Returns all pools (const variant). /// /// The reference is only valid as long as the object that returned it. /// @@ -206,7 +213,7 @@ public: /// @return a collection of all pools const PoolCollection& getPools(Lease::Type type) const; - /// @brief Returns the number of possible leases for specified lease type + /// @brief Returns the number of possible leases for specified lease type. /// /// @param type type of the lease uint64_t getPoolCapacity(Lease::Type type) const; @@ -215,17 +222,18 @@ public: /// allowed for a client which belongs to classes. /// /// @param type type of the lease - /// @param client_classes List of classes the client belongs to. + /// @param client_classes list of classes the client belongs to + /// @return number of leases matching lease type and classes uint64_t getPoolCapacity(Lease::Type type, const ClientClasses& client_classes) const; /// @brief Returns textual representation of the subnet (e.g. - /// "2001:db8::/64") + /// "2001:db8::/64"). /// /// @return textual representation virtual std::string toText() const; - /// @brief Resets subnet-id counter to its initial value (1) + /// @brief Resets subnet-id counter to its initial value (1). /// /// This should be called during reconfiguration, before any new /// subnet objects are created. It will ensure that the subnet_id will @@ -268,6 +276,8 @@ public: } /// @brief Returns shared network name. + /// + /// @return shared network name std::string getSharedNetworkName() const { return (shared_network_name_); } @@ -288,7 +298,7 @@ public: shared_network_name_ = shared_network_name; } - /// @brief Returns all pools (non-const variant) + /// @brief Returns all pools (non-const variant). /// /// The reference is only valid as long as the object that returned it. /// @@ -298,7 +308,7 @@ public: protected: - /// @brief Protected constructor + /// @brief Protected constructor. // /// By making the constructor protected, we make sure that no one will /// ever instantiate that class. Subnet4 and Subnet6 should be used instead. @@ -315,13 +325,13 @@ protected: Subnet(const isc::asiolink::IOAddress& prefix, uint8_t len, const SubnetID id); - /// @brief virtual destructor + /// @brief virtual destructor. /// /// A virtual destructor is needed because other classes /// derive from this class. virtual ~Subnet() { }; - /// @brief keeps the subnet-id value + /// @brief keeps the subnet-id value. /// /// It is incremented every time a new Subnet object is created. It is reset /// (@ref resetSubnetID) every time reconfiguration @@ -330,7 +340,7 @@ protected: /// Static value initialized in subnet.cc. static SubnetID static_id_; - /// @brief returns the next unique Subnet-ID + /// @brief returns the next unique Subnet-ID. /// /// This method generates and returns the next unique subnet-id. /// It is a strictly monotonously increasing value (1,2,3,...) for @@ -346,7 +356,7 @@ protected: return (static_id_++); } - /// @brief Checks if used pool type is valid + /// @brief Checks if used pool type is valid. /// /// Allowed type for Subnet4 is Pool::TYPE_V4. /// Allowed types for Subnet6 are Pool::TYPE_{IA,TA,PD}. @@ -356,12 +366,14 @@ protected: /// @throw BadValue if invalid value is used virtual void checkType(Lease::Type type) const = 0; - /// @brief Returns a sum of possible leases in all pools + /// @brief Returns a sum of possible leases in all pools. + /// /// @param pools list of pools /// @return sum of possible leases uint64_t sumPoolCapacity(const PoolCollection& pools) const; - /// @brief Returns a sum of possible leases in all pools allowing classes + /// @brief Returns a sum of possible leases in all pools allowing classes. + /// /// @param pools list of pools /// @param client_classes list of classes /// @return sum of possible/allowed leases @@ -375,7 +387,7 @@ protected: /// it overlaps with any existing pool within this subnet. /// /// @return true if pool overlaps with an existing pool of a specified - /// type. + /// type, false otherwise bool poolOverlaps(const Lease::Type& pool_type, const PoolPtr& pool) const; /// @brief Unparse a subnet object. @@ -400,22 +412,22 @@ protected: /// a Subnet4 or Subnet6. SubnetID id_; - /// @brief collection of IPv4 or non-temporary IPv6 pools in that subnet + /// @brief collection of IPv4 or non-temporary IPv6 pools in that subnet. PoolCollection pools_; - /// @brief collection of IPv6 temporary address pools in that subnet + /// @brief collection of IPv6 temporary address pools in that subnet. PoolCollection pools_ta_; - /// @brief collection of IPv6 prefix pools in that subnet + /// @brief collection of IPv6 prefix pools in that subnet. PoolCollection pools_pd_; - /// @brief a prefix of the subnet + /// @brief a prefix of the subnet. isc::asiolink::IOAddress prefix_; - /// @brief a prefix length of the subnet + /// @brief a prefix length of the subnet. uint8_t prefix_len_; - /// @brief last allocated address + /// @brief last allocated address. /// /// This is the last allocated address that was previously allocated from /// this particular subnet. Some allocation algorithms (e.g. iterative) use @@ -426,12 +438,12 @@ protected: /// fully trusted. isc::asiolink::IOAddress last_allocated_ia_; - /// @brief last allocated temporary address + /// @brief last allocated temporary address. /// /// See @ref last_allocated_ia_ for details. isc::asiolink::IOAddress last_allocated_ta_; - /// @brief last allocated IPv6 prefix + /// @brief last allocated IPv6 prefix. /// /// See @ref last_allocated_ia_ for details. isc::asiolink::IOAddress last_allocated_pd_; @@ -442,7 +454,7 @@ protected: /// @note: This map is protected by the mutex. std::map last_allocated_time_; - /// @brief Name of the network interface (if connected directly) + /// @brief Name of the network interface (if connected directly). std::string iface_; /// @brief Shared network name. @@ -450,13 +462,15 @@ protected: private: - /// @brief returns the last address that was tried from this subnet + /// @brief returns the last address that was tried from this subnet. + /// + /// Should be called in a thread safe context. /// /// This method returns the last address that was attempted to be allocated /// from this subnet. This is used as helper information for the next /// iteration of the allocation algorithm. /// - /// @todo: Define map somewhere in the + /// @todo: Define map somewhere in the /// AllocEngine::IterativeAllocator and keep the data there /// /// @param type lease type to be returned @@ -466,6 +480,8 @@ private: /// @brief Returns the timestamp when the @c setLastAllocated function /// was called. /// + /// Should be called in a thread safe context. + /// /// @param lease_type Lease type for which last allocation timestamp should /// be returned. /// @@ -475,7 +491,9 @@ private: boost::posix_time::ptime getLastAllocatedTimeInternal(const Lease::Type& lease_type) const; - /// @brief sets the last address that was tried from this subnet + /// @brief sets the last address that was tried from this subnet. + /// + /// Should be called in a thread safe context. /// /// This method sets the last address that was attempted to be allocated /// from this subnet. This is used as helper information for the next @@ -490,7 +508,7 @@ private: void setLastAllocatedInternal(Lease::Type type, const isc::asiolink::IOAddress& addr); - /// @brief The mutex protecting the last_allocated_time_ map. + /// @brief Mutex to protect the internal state. boost::scoped_ptr mutex_; }; @@ -514,7 +532,7 @@ typedef boost::shared_ptr Subnet4Ptr; class Subnet4 : public Subnet, public Network4 { public: - /// @brief Constructor with all parameters + /// @brief Constructor with all parameters. /// /// This constructor calls Subnet::Subnet, where subnet-id is generated. /// @@ -627,13 +645,14 @@ public: private: - /// @brief Returns default address for pool selection + /// @brief Returns default address for pool selection. + /// /// @return ANY IPv4 address virtual isc::asiolink::IOAddress default_pool() const { return (isc::asiolink::IOAddress("0.0.0.0")); } - /// @brief Checks if used pool type is valid + /// @brief Checks if used pool type is valid. /// /// Allowed type for Subnet4 is Pool::TYPE_V4. /// @@ -661,7 +680,7 @@ typedef boost::shared_ptr Subnet6Ptr; class Subnet6 : public Subnet, public Network6 { public: - /// @brief Constructor with all parameters + /// @brief Constructor with all parameters. /// /// This constructor calls Subnet::Subnet, where subnet-id is generated. /// @@ -797,7 +816,7 @@ struct SubnetServerIdIndexTag { }; /// @brief Tag for the index for searching by subnet modification time. struct SubnetModificationTimeIndexTag { }; -/// @brief A collection of @c Subnet4 objects +/// @brief A collection of @c Subnet4 objects. /// /// This container provides a set of indexes which can be used to retrieve /// subnets by various properties. diff --git a/src/lib/dhcpsrv/tests/shared_network_unittest.cc b/src/lib/dhcpsrv/tests/shared_network_unittest.cc index 7179e78326..678703a7cb 100644 --- a/src/lib/dhcpsrv/tests/shared_network_unittest.cc +++ b/src/lib/dhcpsrv/tests/shared_network_unittest.cc @@ -1,10 +1,11 @@ -// Copyright (C) 2017-2019 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2017-2020 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. #include + #include #include #include @@ -12,6 +13,8 @@ #include #include #include +#include + #include #include #include @@ -440,6 +443,90 @@ TEST(SharedNetwork4Test, getPreferredSubnet) { EXPECT_EQ(subnet3->getID(), preferred->getID()); } +// This test verifies that preferred subnet is returned based on the timestamp +// when the subnet was last used and allowed client classes. +TEST(SharedNetwork4Test, getPreferredSubnetMultiThreading) { + MultiThreadingMgr::instance().setMode(true); + SharedNetwork4Ptr network(new SharedNetwork4("frog")); + + // Create four subnets. + Subnet4Ptr subnet1(new Subnet4(IOAddress("10.0.0.0"), 8, 10, 20, 30, + SubnetID(1))); + Subnet4Ptr subnet2(new Subnet4(IOAddress("192.0.2.0"), 24, 10, 20, 30, + SubnetID(2))); + Subnet4Ptr subnet3(new Subnet4(IOAddress("172.16.25.0"), 24, 10, 20, 30, + SubnetID(3))); + Subnet4Ptr subnet4(new Subnet4(IOAddress("172.16.28.0"), 24, 10, 20, 30, + SubnetID(4))); + + // Associate first two subnets with classes. + subnet1->allowClientClass("class1"); + subnet2->allowClientClass("class1"); + + std::vector subnets; + subnets.push_back(subnet1); + subnets.push_back(subnet2); + subnets.push_back(subnet3); + subnets.push_back(subnet4); + + // Subnets have unique IDs so they should successfully be added to the + // network. + for (auto i = 0; i < subnets.size(); ++i) { + ASSERT_NO_THROW(network->add(subnets[i])) + << "failed to add subnet with id " << subnets[i]->getID() + << " to shared network"; + } + + Subnet4Ptr preferred; + + // Initially, for every subnet we should get the same subnet as the preferred + // one, because none of them have been used. + for (auto i = 0; i < subnets.size(); ++i) { + preferred = network->getPreferredSubnet(subnets[i]); + EXPECT_EQ(subnets[i]->getID(), preferred->getID()); + } + + // Allocating an address from subnet2 updates the last allocated timestamp + // for this subnet, which makes this subnet preferred over subnet1. + subnet2->setLastAllocated(Lease::TYPE_V4, IOAddress("192.0.2.25")); + preferred = network->getPreferredSubnet(subnet1); + EXPECT_EQ(subnet2->getID(), preferred->getID()); + + // If selected is subnet2, the same is returned. + preferred = network->getPreferredSubnet(subnet2); + EXPECT_EQ(subnet2->getID(), preferred->getID()); + + // Even though the subnet1 has been most recently used, the preferred + // subnet is subnet3 in this case, because of the client class + // mismatch. + preferred = network->getPreferredSubnet(subnet3); + EXPECT_EQ(subnet3->getID(), preferred->getID()); + + // Same for subnet4. + preferred = network->getPreferredSubnet(subnet4); + EXPECT_EQ(subnet4->getID(), preferred->getID()); + + // Allocate an address from the subnet3. This makes it preferred to + // subnet4. + subnet3->setLastAllocated(Lease::TYPE_V4, IOAddress("172.16.25.23")); + + // If the selected is subnet1, the preferred subnet is subnet2, because + // it has the same set of classes as subnet1. The subnet3 can't be + // preferred here because of the client class mismatch. + preferred = network->getPreferredSubnet(subnet1); + EXPECT_EQ(subnet2->getID(), preferred->getID()); + + // If we select subnet4, the preferred subnet is subnet3 because + // it was used more recently. + preferred = network->getPreferredSubnet(subnet4); + EXPECT_EQ(subnet3->getID(), preferred->getID()); + + // Repeat the test for subnet3 being a selected subnet. + preferred = network->getPreferredSubnet(subnet3); + EXPECT_EQ(subnet3->getID(), preferred->getID()); + MultiThreadingMgr::instance().setMode(false); +} + // This test verifies that subnetsIncludeMatchClientId() works as expected. TEST(SharedNetwork4Test, subnetsIncludeMatchClientId) { SharedNetwork4Ptr network(new SharedNetwork4("frog")); @@ -1095,6 +1182,106 @@ TEST(SharedNetwork6Test, getPreferredSubnet) { EXPECT_EQ(subnet3->getID(), preferred->getID()); } +// This test verifies that preferred subnet is returned based on the timestamp +// when the subnet was last used and allowed client classes. +TEST(SharedNetwork6Test, getPreferredSubnetMultiThreading) { + MultiThreadingMgr::instance().setMode(true); + SharedNetwork6Ptr network(new SharedNetwork6("frog")); + + // Create four subnets. + Subnet6Ptr subnet1(new Subnet6(IOAddress("2001:db8:1::"), 64, 10, 20, 30, + 40, SubnetID(1))); + Subnet6Ptr subnet2(new Subnet6(IOAddress("3000::"), 16, 10, 20, 30, 40, + SubnetID(2))); + Subnet6Ptr subnet3(new Subnet6(IOAddress("2001:db8:2::"), 64, 10, 20, 30, + 40, SubnetID(3))); + Subnet6Ptr subnet4(new Subnet6(IOAddress("3000:1::"), 64, 10, 20, 30, + 40, SubnetID(4))); + + + // Associate first two subnets with classes. + subnet1->allowClientClass("class1"); + subnet2->allowClientClass("class1"); + + std::vector subnets; + subnets.push_back(subnet1); + subnets.push_back(subnet2); + subnets.push_back(subnet3); + subnets.push_back(subnet4); + + // Subnets have unique IDs so they should successfully be added to the + // network. + for (auto i = 0; i < subnets.size(); ++i) { + ASSERT_NO_THROW(network->add(subnets[i])) + << "failed to add subnet with id " << subnets[i]->getID() + << " to shared network"; + } + + Subnet6Ptr preferred; + + // Initially, for every subnet we should get the same subnet as the preferred + // one, because none of them have been used. + for (auto i = 0; i < subnets.size(); ++i) { + preferred = network->getPreferredSubnet(subnets[i], Lease::TYPE_NA); + EXPECT_EQ(subnets[i]->getID(), preferred->getID()); + preferred = network->getPreferredSubnet(subnets[i], Lease::TYPE_TA); + EXPECT_EQ(subnets[i]->getID(), preferred->getID()); + preferred = network->getPreferredSubnet(subnets[i], Lease::TYPE_PD); + EXPECT_EQ(subnets[i]->getID(), preferred->getID()); + } + + // Allocating an address from subnet2 updates the last allocated timestamp + // for this subnet, which makes this subnet preferred over subnet1. + subnet2->setLastAllocated(Lease::TYPE_NA, IOAddress("2001:db8:1:2::")); + preferred = network->getPreferredSubnet(subnet1, Lease::TYPE_NA); + EXPECT_EQ(subnet2->getID(), preferred->getID()); + + // If selected is subnet2, the same is returned. + preferred = network->getPreferredSubnet(subnet2, Lease::TYPE_NA); + EXPECT_EQ(subnet2->getID(), preferred->getID()); + + // The preferred subnet is dependent on the lease type. For the PD + // we should get the same subnet as selected. + preferred = network->getPreferredSubnet(subnet1, Lease::TYPE_PD); + EXPECT_EQ(subnet1->getID(), preferred->getID()); + + // Although, if we pick a prefix from the subnet2, we should get the + // subnet2 as preferred instead. + subnet2->setLastAllocated(Lease::TYPE_PD, IOAddress("3000:1234::")); + preferred = network->getPreferredSubnet(subnet1, Lease::TYPE_PD); + EXPECT_EQ(subnet2->getID(), preferred->getID()); + + // Even though the subnet1 has been most recently used, the preferred + // subnet is subnet3 in this case, because of the client class + // mismatch. + preferred = network->getPreferredSubnet(subnet3, Lease::TYPE_NA); + EXPECT_EQ(subnet3->getID(), preferred->getID()); + + // Same for subnet4. + preferred = network->getPreferredSubnet(subnet4, Lease::TYPE_NA); + EXPECT_EQ(subnet4->getID(), preferred->getID()); + + // Allocate an address from the subnet3. This makes it preferred to + // subnet4. + subnet3->setLastAllocated(Lease::TYPE_NA, IOAddress("2001:db8:2:1234::")); + + // If the selected is subnet1, the preferred subnet is subnet2, because + // it has the same set of classes as subnet1. The subnet3 can't be + // preferred here because of the client class mismatch. + preferred = network->getPreferredSubnet(subnet1, Lease::TYPE_NA); + EXPECT_EQ(subnet2->getID(), preferred->getID()); + + // If we select subnet4, the preferred subnet is subnet3 because + // it was used more recently. + preferred = network->getPreferredSubnet(subnet4, Lease::TYPE_NA); + EXPECT_EQ(subnet3->getID(), preferred->getID()); + + // Repeat the test for subnet3 being a selected subnet. + preferred = network->getPreferredSubnet(subnet3, Lease::TYPE_NA); + EXPECT_EQ(subnet3->getID(), preferred->getID()); + MultiThreadingMgr::instance().setMode(false); +} + // This test verifies that subnetsAllHRGlobal() works as expected. TEST(SharedNetwork6Test, subnetsAllHRGlobal) { SharedNetwork6Ptr network(new SharedNetwork6("frog")); diff --git a/src/lib/dhcpsrv/tests/subnet_unittest.cc b/src/lib/dhcpsrv/tests/subnet_unittest.cc index 160c2a4caa..c36d987c40 100644 --- a/src/lib/dhcpsrv/tests/subnet_unittest.cc +++ b/src/lib/dhcpsrv/tests/subnet_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2012-2019 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2012-2020 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -683,7 +684,6 @@ TEST(Subnet4Test, get) { EXPECT_EQ(28, subnet->get().second); } - // Checks if last allocated address/prefix is stored/retrieved properly TEST(Subnet4Test, lastAllocated) { IOAddress addr("192.0.2.17"); @@ -705,6 +705,29 @@ TEST(Subnet4Test, lastAllocated) { EXPECT_THROW(subnet->setLastAllocated(Lease::TYPE_PD, addr), BadValue); } +// Checks if last allocated address/prefix is stored/retrieved properly +TEST(Subnet4Test, lastAllocatedMultiThreading) { + MultiThreadingMgr::instance().setMode(true); + IOAddress addr("192.0.2.17"); + + IOAddress last("192.0.2.255"); + + Subnet4Ptr subnet(new Subnet4(IOAddress("192.0.2.0"), 24, 1, 2, 3)); + + // Check initial conditions (all should be set to the last address in range) + EXPECT_EQ(last.toText(), subnet->getLastAllocated(Lease::TYPE_V4).toText()); + + // Now set last allocated for IA + EXPECT_NO_THROW(subnet->setLastAllocated(Lease::TYPE_V4, addr)); + EXPECT_EQ(addr.toText(), subnet->getLastAllocated(Lease::TYPE_V4).toText()); + + // No, you can't set the last allocated IPv6 address in IPv4 subnet + EXPECT_THROW(subnet->setLastAllocated(Lease::TYPE_TA, addr), BadValue); + EXPECT_THROW(subnet->setLastAllocated(Lease::TYPE_TA, addr), BadValue); + EXPECT_THROW(subnet->setLastAllocated(Lease::TYPE_PD, addr), BadValue); + MultiThreadingMgr::instance().setMode(false); +} + // Checks if the V4 is the only allowed type for Pool4 and if getPool() // is working properly. TEST(Subnet4Test, PoolType) { @@ -1732,6 +1755,43 @@ TEST(Subnet6Test, lastAllocated) { EXPECT_THROW(subnet->setLastAllocated(Lease::TYPE_V4, ia), BadValue); } +// Checks if last allocated address/prefix is stored/retrieved properly +TEST(Subnet6Test, lastAllocatedMultiThreading) { + MultiThreadingMgr::instance().setMode(true); + IOAddress ia("2001:db8:1::1"); + IOAddress ta("2001:db8:1::abcd"); + IOAddress pd("2001:db8:1::1234:5678"); + + IOAddress last("2001:db8:1::ffff:ffff:ffff:ffff"); + + Subnet6Ptr subnet(new Subnet6(IOAddress("2001:db8:1::"), 64, 1, 2, 3, 4)); + + // Check initial conditions (all should be set to the last address in range) + EXPECT_EQ(last.toText(), subnet->getLastAllocated(Lease::TYPE_NA).toText()); + EXPECT_EQ(last.toText(), subnet->getLastAllocated(Lease::TYPE_TA).toText()); + EXPECT_EQ(last.toText(), subnet->getLastAllocated(Lease::TYPE_PD).toText()); + + // Now set last allocated for IA + EXPECT_NO_THROW(subnet->setLastAllocated(Lease::TYPE_NA, ia)); + EXPECT_EQ(ia.toText(), subnet->getLastAllocated(Lease::TYPE_NA).toText()); + + // TA and PD should be unchanged + EXPECT_EQ(last.toText(), subnet->getLastAllocated(Lease::TYPE_TA).toText()); + EXPECT_EQ(last.toText(), subnet->getLastAllocated(Lease::TYPE_PD).toText()); + + // Now set TA and PD + EXPECT_NO_THROW(subnet->setLastAllocated(Lease::TYPE_TA, ta)); + EXPECT_NO_THROW(subnet->setLastAllocated(Lease::TYPE_PD, pd)); + + EXPECT_EQ(ia.toText(), subnet->getLastAllocated(Lease::TYPE_NA).toText()); + EXPECT_EQ(ta.toText(), subnet->getLastAllocated(Lease::TYPE_TA).toText()); + EXPECT_EQ(pd.toText(), subnet->getLastAllocated(Lease::TYPE_PD).toText()); + + // No, you can't set the last allocated IPv4 address in IPv6 subnet + EXPECT_THROW(subnet->setLastAllocated(Lease::TYPE_V4, ia), BadValue); + MultiThreadingMgr::instance().setMode(false); +} + // This test verifies that the IPv4 subnet can be fetched by id. TEST(SubnetFetcherTest, getSubnet4ById) { Subnet4Collection collection;