From: Marcin Siodelski Date: Tue, 4 Apr 2023 20:45:18 +0000 (+0200) Subject: [#2823] Common methods for instantiating allocators X-Git-Tag: Kea-2.3.7~28 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=11c84088a86db51eeea8aa5aac2a6c5fe9ee6594;p=thirdparty%2Fkea.git [#2823] Common methods for instantiating allocators The logic creating allocators and allocation states have been moved to the Subnet. It can now be reused in the config backend fetch. --- diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc index c5ffd3e1f7..2aa74afc8b 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc +++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc @@ -11,12 +11,6 @@ #include #include #include -#include -#include -#include -#include -#include -#include #include #include #include @@ -726,29 +720,8 @@ Subnet4ConfigParser::parse(ConstElementPtr subnet) { auto network4 = boost::dynamic_pointer_cast(sn4ptr); parseAllocatorParams(subnet, network4); - if (sn4ptr->getAllocatorType() == "random") { - sn4ptr->setAllocator(Lease::TYPE_V4, - boost::make_shared - (Lease::TYPE_V4, sn4ptr)); - sn4ptr->setAllocationState(Lease::TYPE_V4, SubnetAllocationStatePtr()); - - for (auto pool : *pools_) { - pool->setAllocationState(PoolRandomAllocationState::create(pool)); - } - - } else if (sn4ptr->getAllocatorType() == "flq") { - sn4ptr->setAllocator(Lease::TYPE_V4, - boost::make_shared - (Lease::TYPE_V4, sn4ptr)); - for (auto pool : *pools_) { - pool->setAllocationState(PoolFreeLeaseQueueAllocationState::create(pool)); - } - - } else { - for (auto pool : *pools_) { - pool->setAllocationState(PoolIterativeAllocationState::create(pool)); - } - } + // Instantiate the allocator. + sn4ptr->createAllocators(); return (sn4ptr); } @@ -1270,64 +1243,8 @@ Subnet6ConfigParser::parse(ConstElementPtr subnet) { auto network6 = boost::dynamic_pointer_cast(sn6ptr); parsePdAllocatorParams(subnet, network6); - // If we use the random allocator we need to create its instance and - // the state instance for it. There is no need to do it for the iterative - // allocator because it is configured by default. - if (sn6ptr->getAllocatorType() == "random") { - sn6ptr->setAllocator(Lease::TYPE_NA, - boost::make_shared - (Lease::TYPE_NA, sn6ptr)); - sn6ptr->setAllocator(Lease::TYPE_TA, - boost::make_shared - (Lease::TYPE_TA, sn6ptr)); - sn6ptr->setAllocationState(Lease::TYPE_NA, SubnetAllocationStatePtr()); - sn6ptr->setAllocationState(Lease::TYPE_TA, SubnetAllocationStatePtr()); - - } else if (sn6ptr->getAllocatorType() == "flq") { - isc_throw(BadValue, "Free Lease Queue allocator is not supported for IPv6 address pools"); - } - - // Repeat the same for the delegated prefix allocator. - if (sn6ptr->getPdAllocatorType() == "random") { - sn6ptr->setAllocator(Lease::TYPE_PD, - boost::make_shared - (Lease::TYPE_PD, sn6ptr)); - sn6ptr->setAllocationState(Lease::TYPE_PD, SubnetAllocationStatePtr()); - - } else if (sn6ptr->getPdAllocatorType() == "flq") { - sn6ptr->setAllocator(Lease::TYPE_PD, - boost::make_shared - (Lease::TYPE_PD, sn6ptr)); - sn6ptr->setAllocationState(Lease::TYPE_PD, SubnetAllocationStatePtr()); - } - - // Create states for the pools. - for (auto pool : *pools_) { - switch (pool->getType()) { - case Lease::TYPE_NA: - case Lease::TYPE_TA: - if (sn6ptr->getAllocatorType() == "random") { - pool->setAllocationState(PoolRandomAllocationState::create(pool)); - - } else { - pool->setAllocationState(PoolIterativeAllocationState::create(pool)); - } - break; - case Lease::TYPE_PD: - if (sn6ptr->getPdAllocatorType() == "random") { - pool->setAllocationState(PoolRandomAllocationState::create(pool)); - - } else if (sn6ptr->getPdAllocatorType() == "flq") { - pool->setAllocationState(PoolFreeLeaseQueueAllocationState::create(pool)); - - } else { - pool->setAllocationState(PoolIterativeAllocationState::create(pool)); - } - break; - default: - continue; - } - } + // Instantiate the allocators. + sn6ptr->createAllocators(); return (sn6ptr); } diff --git a/src/lib/dhcpsrv/subnet.cc b/src/lib/dhcpsrv/subnet.cc index 762589c0d8..dbd7108107 100644 --- a/src/lib/dhcpsrv/subnet.cc +++ b/src/lib/dhcpsrv/subnet.cc @@ -9,7 +9,12 @@ #include #include #include +#include +#include +#include #include +#include +#include #include #include #include @@ -743,6 +748,33 @@ Subnet::toElement() const { return (map); } +void +Subnet4::createAllocators() { + if (getAllocatorType() == "random") { + setAllocator(Lease::TYPE_V4, + boost::make_shared + (Lease::TYPE_V4, shared_from_this())); + setAllocationState(Lease::TYPE_V4, SubnetAllocationStatePtr()); + + for (auto pool : pools_) { + pool->setAllocationState(PoolRandomAllocationState::create(pool)); + } + + } else if (getAllocatorType() == "flq") { + setAllocator(Lease::TYPE_V4, + boost::make_shared + (Lease::TYPE_V4, shared_from_this())); + for (auto pool : pools_) { + pool->setAllocationState(PoolFreeLeaseQueueAllocationState::create(pool)); + } + + } else { + for (auto pool : pools_) { + pool->setAllocationState(PoolIterativeAllocationState::create(pool)); + } + } +} + data::ElementPtr Subnet4::toElement() const { // Prepare the map @@ -777,6 +809,66 @@ Subnet4::parsePrefix(const std::string& prefix) { return (parsed); } +void +Subnet6::createAllocators() { + // If we use the random allocator we need to create its instance and + // the state instance for it. There is no need to do it for the iterative + // allocator because it is configured by default. + if (getAllocatorType() == "random") { + setAllocator(Lease::TYPE_NA, + boost::make_shared + (Lease::TYPE_NA, shared_from_this())); + setAllocator(Lease::TYPE_TA, + boost::make_shared + (Lease::TYPE_TA, shared_from_this())); + setAllocationState(Lease::TYPE_NA, SubnetAllocationStatePtr()); + setAllocationState(Lease::TYPE_TA, SubnetAllocationStatePtr()); + + } else if (getAllocatorType() == "flq") { + isc_throw(BadValue, "Free Lease Queue allocator is not supported for IPv6 address pools"); + } + + // Repeat the same for the delegated prefix allocator. + if (getPdAllocatorType() == "random") { + setAllocator(Lease::TYPE_PD, + boost::make_shared + (Lease::TYPE_PD, shared_from_this())); + setAllocationState(Lease::TYPE_PD, SubnetAllocationStatePtr()); + + } else if (getPdAllocatorType() == "flq") { + setAllocator(Lease::TYPE_PD, + boost::make_shared + (Lease::TYPE_PD, shared_from_this())); + setAllocationState(Lease::TYPE_PD, SubnetAllocationStatePtr()); + } + // Create allocation states for NA pools. + for (auto pool : pools_) { + if (getAllocatorType() == "random") { + pool->setAllocationState(PoolRandomAllocationState::create(pool)); + } else { + pool->setAllocationState(PoolIterativeAllocationState::create(pool)); + } + } + // Create allocation states for TA pools. + for (auto pool : pools_ta_) { + if (getAllocatorType() == "random") { + pool->setAllocationState(PoolRandomAllocationState::create(pool)); + } else { + pool->setAllocationState(PoolIterativeAllocationState::create(pool)); + } + } + // Create allocation states for PD pools. + for (auto pool : pools_pd_) { + if (getPdAllocatorType() == "random") { + pool->setAllocationState(PoolRandomAllocationState::create(pool)); + } else if (getPdAllocatorType() == "flq") { + pool->setAllocationState(PoolFreeLeaseQueueAllocationState::create(pool)); + } else { + pool->setAllocationState(PoolIterativeAllocationState::create(pool)); + } + } +} + data::ElementPtr Subnet6::toElement() const { // Prepare the map diff --git a/src/lib/dhcpsrv/subnet.h b/src/lib/dhcpsrv/subnet.h index a388d5f18a..891d20d424 100644 --- a/src/lib/dhcpsrv/subnet.h +++ b/src/lib/dhcpsrv/subnet.h @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -316,6 +317,15 @@ public: /// @param allocation_state allocation state instance. void setAllocationState(Lease::Type type, const SubnetAllocationStatePtr& allocation_state); + /// @brief Instantiates the allocators and their states. + /// + /// It determines the types of the allocators to create using the list of + /// the allocator types specified with the @c Network::setAllocatorType method. + /// + /// This function is called from the subnet parsers and after fetching + /// the subnet configuration from a configuration backend. + virtual void createAllocators() = 0; + /// @brief Calls @c initAfterConfigure for each allocator. void initAllocatorsAfterConfigure(); @@ -490,7 +500,7 @@ typedef boost::shared_ptr Subnet4Ptr; /// This class represents an IPv4 subnet. /// @note Subnet and Network use virtual inheritance to avoid /// a diamond issue with UserContext -class Subnet4 : public Subnet, public Network4 { +class Subnet4 : public Subnet, public Network4, public boost::enable_shared_from_this { public: /// @brief Constructor with all parameters. @@ -601,6 +611,15 @@ public: /// @return A pointer to unparsed subnet configuration. virtual data::ElementPtr toElement() const; + /// @brief Instantiates the allocator and its state. + /// + /// It uses the type of the allocator specified with the + /// @c Network::setAllocatorType method. + /// + /// This function is called from the subnet parsers and after fetching + /// the subnet configuration from a configuration backend. + virtual void createAllocators(); + /// @brief Converts subnet prefix to a pair of prefix/length pair. /// /// @param prefix Prefix to be parsed. @@ -648,7 +667,7 @@ typedef boost::shared_ptr Subnet6Ptr; /// This class represents an IPv6 subnet. /// @note Subnet and Network use virtual inheritance to avoid /// a diamond issue with UserContext -class Subnet6 : public Subnet, public Network6 { +class Subnet6 : public Subnet, public Network6, public boost::enable_shared_from_this { public: /// @brief Constructor with all parameters. @@ -742,6 +761,15 @@ public: virtual bool clientSupported(const isc::dhcp::ClientClasses& client_classes) const; + /// @brief Instantiates the allocators and their states. + /// + /// It determines the types of the allocators to create using the list of + /// the allocator types specified with the @c Network::setAllocatorType method. + /// + /// This function is called from the subnet parsers and after fetching + /// the subnet configuration from a configuration backend. + virtual void createAllocators(); + /// @brief Unparse a subnet object. /// /// @return A pointer to unparsed subnet configuration. diff --git a/src/lib/dhcpsrv/tests/subnet_unittest.cc b/src/lib/dhcpsrv/tests/subnet_unittest.cc index 85de81ee0b..304ca88ba9 100644 --- a/src/lib/dhcpsrv/tests/subnet_unittest.cc +++ b/src/lib/dhcpsrv/tests/subnet_unittest.cc @@ -14,6 +14,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include #include #include @@ -763,6 +769,70 @@ TEST(Subnet4Test, getServerId) { EXPECT_EQ("1.2.3.4", subnet.getServerId().toText()); } +// This test verifies that an iterative allocator and the corresponding +// states are instantiated for a subnet. +TEST(Subnet4Test, createAllocatorsIterative) { + // Create a subnet. + auto subnet = Subnet4::create(IOAddress("192.2.0.0"), 16, 1, 2, 3); + ASSERT_TRUE(subnet); + // Create a pool. + auto pool = boost::make_shared(IOAddress("192.2.0.0"), 16); + subnet->addPool(pool); + // Instantiate the allocator. + ASSERT_NO_THROW(subnet->createAllocators()); + // Expect iterative allocator. + EXPECT_TRUE(boost::dynamic_pointer_cast + (subnet->getAllocator(Lease::TYPE_V4))); + // Expect iterative allocation state for the subnet. + EXPECT_TRUE(boost::dynamic_pointer_cast + (subnet->getAllocationState(Lease::TYPE_V4))); + // Expect iterative allocation state for the pool. + EXPECT_TRUE(boost::dynamic_pointer_cast + (pool->getAllocationState())); +} + +// This test verifies that a random allocator and the corresponding +// states are instantiated for a subnet. +TEST(Subnet4Test, createAllocatorsRandom) { + // Create a subnet. + auto subnet = Subnet4::create(IOAddress("192.2.0.0"), 16, 1, 2, 3); + ASSERT_TRUE(subnet); + // Create a pool. + auto pool = boost::make_shared(IOAddress("192.2.0.0"), 16); + subnet->addPool(pool); + // Select the random allocator. + subnet->setAllocatorType("random"); + // Instantiate the allocator. + ASSERT_NO_THROW(subnet->createAllocators()); + // Expect random allocator. + EXPECT_TRUE(boost::dynamic_pointer_cast + (subnet->getAllocator(Lease::TYPE_V4))); + // Expect random allocation state for the pool. + EXPECT_TRUE(boost::dynamic_pointer_cast + (pool->getAllocationState())); +} + +// This test verifies that an FLQ allocator and the corresponding +// states are instantiated for a subnet. +TEST(Subnet4Test, createAllocatorsFreeLeaseQueue) { + // Create a subnet. + auto subnet = Subnet4::create(IOAddress("192.2.0.0"), 16, 1, 2, 3); + ASSERT_TRUE(subnet); + // Create a pool. + auto pool = boost::make_shared(IOAddress("192.2.0.0"), 16); + subnet->addPool(pool); + // Select the FLQ allocator. + subnet->setAllocatorType("flq"); + // Instantiate the allocator. + ASSERT_NO_THROW(subnet->createAllocators()); + // Expect FLQ allocator. + EXPECT_TRUE(boost::dynamic_pointer_cast + (subnet->getAllocator(Lease::TYPE_V4))); + // Expect FLQ allocation state for the pool. + EXPECT_TRUE(boost::dynamic_pointer_cast + (pool->getAllocationState())); +} + // Tests for Subnet6 TEST(Subnet6Test, constructor) { @@ -1701,6 +1771,142 @@ TEST(Subnet6Test, rapidCommit) { EXPECT_FALSE(subnet.getRapidCommit()); } +// This test verifies that an iterative allocator and the corresponding +// states are instantiated for a subnet. +TEST(Subnet6Test, createAllocatorsIterative) { + // Create a subnet. + auto subnet = Subnet6::create(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4); + ASSERT_TRUE(subnet); + // NA pool. + auto pool = boost::make_shared(Lease::TYPE_NA, IOAddress("2001:db8:1:1::"), 112); + subnet->addPool(pool); + // TA pool. + auto ta_pool = boost::make_shared(Lease::TYPE_TA, IOAddress("2001:db8:1:2::"), 112); + subnet->addPool(ta_pool); + // PD pool. + auto pd_pool = boost::make_shared(Lease::TYPE_PD, IOAddress("3000::"), 112, 120); + subnet->addPool(pd_pool); + // Instantiate the allocators. + ASSERT_NO_THROW(subnet->createAllocators()); + // Expect iterative allocator for NA. + EXPECT_TRUE(boost::dynamic_pointer_cast + (subnet->getAllocator(Lease::TYPE_NA))); + // Expect iterative allocator for TA. + EXPECT_TRUE(boost::dynamic_pointer_cast + (subnet->getAllocator(Lease::TYPE_TA))); + // Expect iterative allocator for PD. + EXPECT_TRUE(boost::dynamic_pointer_cast + (subnet->getAllocator(Lease::TYPE_PD))); + // Expect iterative allocation state for NA. + EXPECT_TRUE(boost::dynamic_pointer_cast + (subnet->getAllocationState(Lease::TYPE_NA))); + // Expect iterative allocation state for TA. + EXPECT_TRUE(boost::dynamic_pointer_cast + (subnet->getAllocationState(Lease::TYPE_TA))); + // Expect iterative allocation state for PD. + EXPECT_TRUE(boost::dynamic_pointer_cast + (subnet->getAllocationState(Lease::TYPE_PD))); + // Expect iterative allocation state for the NA pool. + EXPECT_TRUE(boost::dynamic_pointer_cast + (pool->getAllocationState())); + // Expect iterative allocation state for the TA pool. + EXPECT_TRUE(boost::dynamic_pointer_cast + (pool->getAllocationState())); + // Expect iterative allocation state for the PD pool. + EXPECT_TRUE(boost::dynamic_pointer_cast + (pd_pool->getAllocationState())); +} + +// This test verifies that a random allocator and the corresponding +// states are instantiated for a subnet. +TEST(Subnet6Test, createAllocatorsRandom) { + // Create a subnet. + auto subnet = Subnet6::create(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4); + ASSERT_TRUE(subnet); + // NA pool. + auto pool = boost::make_shared(Lease::TYPE_NA, IOAddress("2001:db8:1:1::"), 112); + subnet->addPool(pool); + // TA pool. + auto ta_pool = boost::make_shared(Lease::TYPE_TA, IOAddress("2001:db8:1:2::"), 112); + subnet->addPool(ta_pool); + // PD pool. + auto pd_pool = boost::make_shared(Lease::TYPE_PD, IOAddress("3000::"), 112, 120); + subnet->addPool(pd_pool); + // Select the random allocators. + subnet->setAllocatorType("random"); + subnet->setPdAllocatorType("random"); + // Instantiate the allocators. + ASSERT_NO_THROW(subnet->createAllocators()); + // Expect random allocator for NA. + EXPECT_TRUE(boost::dynamic_pointer_cast + (subnet->getAllocator(Lease::TYPE_NA))); + // Expect random allocator for TA. + EXPECT_TRUE(boost::dynamic_pointer_cast + (subnet->getAllocator(Lease::TYPE_TA))); + // Expect random allocator for PD. + EXPECT_TRUE(boost::dynamic_pointer_cast + (subnet->getAllocator(Lease::TYPE_PD))); + // Expect random allocation state for the NA pool. + EXPECT_TRUE(boost::dynamic_pointer_cast + (pool->getAllocationState())); + // Expect random allocation state for the TA pool. + EXPECT_TRUE(boost::dynamic_pointer_cast + (pool->getAllocationState())); + // Expect random allocation state for the PD pool. + EXPECT_TRUE(boost::dynamic_pointer_cast + (pd_pool->getAllocationState())); +} + +// This test verifies that a FLQ allocator and the corresponding +// states are instantiated for a subnet. +TEST(Subnet6Test, createAllocatorsFreeLeaseQueue) { + // Create a subnet. + auto subnet = Subnet6::create(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4); + ASSERT_TRUE(subnet); + // NA pool. + auto pool = boost::make_shared(Lease::TYPE_NA, IOAddress("2001:db8:1:1::"), 112); + subnet->addPool(pool); + // TA pool. + auto ta_pool = boost::make_shared(Lease::TYPE_TA, IOAddress("2001:db8:1:2::"), 112); + subnet->addPool(ta_pool); + // PD pool. + auto pd_pool = boost::make_shared(Lease::TYPE_PD, IOAddress("3000::"), 112, 120); + subnet->addPool(pd_pool); + // Select the random allocator for addresses. + subnet->setAllocatorType("random"); + // Select the FLQ allocator for the prefix delegation. + subnet->setPdAllocatorType("flq"); + // Instantiate the allocators. + ASSERT_NO_THROW(subnet->createAllocators()); + // Expect random allocator for NA. + EXPECT_TRUE(boost::dynamic_pointer_cast + (subnet->getAllocator(Lease::TYPE_NA))); + // Expect random allocator for TA. + EXPECT_TRUE(boost::dynamic_pointer_cast + (subnet->getAllocator(Lease::TYPE_TA))); + // Expect FLQ allocator for PD. + EXPECT_TRUE(boost::dynamic_pointer_cast + (subnet->getAllocator(Lease::TYPE_PD))); + // Expect random allocation state for the NA pool. + EXPECT_TRUE(boost::dynamic_pointer_cast + (pool->getAllocationState())); + // Expect random allocation state for the TA pool. + EXPECT_TRUE(boost::dynamic_pointer_cast + (pool->getAllocationState())); + // Expect FLQ allocation state for the PD pool. + EXPECT_TRUE(boost::dynamic_pointer_cast + (pd_pool->getAllocationState())); +} + +// Test that it is not allowed to use the FLQ allocator for the address pools. +TEST(Subnet6Test, createAllocatorsFreeLeaseQueueNotAllowed) { + auto subnet = Subnet6::create(IOAddress("2001:db8:1::"), 56, 1, 2, 3, 4); + ASSERT_TRUE(subnet); + + subnet->setAllocatorType("flq"); + EXPECT_THROW(subnet->createAllocators(), BadValue); +} + // This test verifies that the IPv4 subnet can be fetched by id. TEST(SubnetFetcherTest, getSubnet4ById) { Subnet4Collection collection;