#include <dhcpsrv/shared_network.h>
#include <dhcpsrv/subnet.h>
#include <util/multi_threading_mgr.h>
+
#include <boost/lexical_cast.hpp>
#include <boost/make_shared.hpp>
+
#include <algorithm>
#include <sstream>
last_allocated_time_(),
iface_(),
shared_network_name_(),
- mutex_() {
+ mutex_(boost::make_shared<std::mutex>()) {
if ((prefix.isV6() && len > 128) ||
(prefix.isV4() && len > 32)) {
isc_throw(BadValue,
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
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
/// @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
///
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
/// @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
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<isc::asiolink::IOAddress, uint8_t> get() const {
/// 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
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
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
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.
///
/// @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;
/// 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
}
/// @brief Returns shared network name.
+ ///
+ /// @return shared network name
std::string getSharedNetworkName() const {
return (shared_network_name_);
}
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.
///
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.
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
/// 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
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}.
/// @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
/// 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.
/// 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
/// 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_;
/// @note: This map is protected by the mutex.
std::map<Lease::Type, boost::posix_time::ptime> 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.
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<SubnetID, ClientClass, IOAddress> somewhere in the
+ /// @todo: Define map<SubnetID, ClientClass, IOAddress> somewhere in the
/// AllocEngine::IterativeAllocator and keep the data there
///
/// @param type lease type to be returned
/// @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.
///
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
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<std::mutex> mutex_;
};
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.
///
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.
///
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.
///
/// @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.
-// 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 <config.h>
+
#include <asiolink/io_address.h>
#include <dhcpsrv/shared_network.h>
#include <dhcpsrv/subnet.h>
#include <dhcpsrv/triplet.h>
#include <exceptions/exceptions.h>
#include <testutils/test_to_element.h>
+#include <util/multi_threading_mgr.h>
+
#include <gtest/gtest.h>
#include <cstdint>
#include <vector>
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<Subnet4Ptr> 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"));
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<Subnet6Ptr> 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"));
-// 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
#include <dhcpsrv/shared_network.h>
#include <dhcpsrv/subnet.h>
#include <exceptions/exceptions.h>
+#include <util/multi_threading_mgr.h>
#include <boost/pointer_cast.hpp>
#include <boost/scoped_ptr.hpp>
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");
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) {
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;