From 7f881ef1534c3d0b4809a6b9e2650b26bfa571f3 Mon Sep 17 00:00:00 2001 From: Marcin Siodelski Date: Thu, 16 Mar 2023 19:09:05 +0100 Subject: [PATCH] [#2780] Configure FLQ allocator --- src/bin/dhcp4/ctrl_dhcp4_srv.cc | 13 +++- src/bin/dhcp6/ctrl_dhcp6_srv.cc | 10 +++ src/lib/dhcpsrv/dhcpsrv_messages.mes | 18 ++++++ src/lib/dhcpsrv/flq_allocator.cc | 13 ++++ .../dhcpsrv/parsers/base_network_parser.cc | 10 +-- src/lib/dhcpsrv/parsers/dhcp_parsers.cc | 33 ++++++++-- .../dhcpsrv/tests/dhcp_parsers_unittest.cc | 61 ++++++++++++++++++- 7 files changed, 145 insertions(+), 13 deletions(-) diff --git a/src/bin/dhcp4/ctrl_dhcp4_srv.cc b/src/bin/dhcp4/ctrl_dhcp4_srv.cc index d739707c74..b6981bf1b3 100644 --- a/src/bin/dhcp4/ctrl_dhcp4_srv.cc +++ b/src/bin/dhcp4/ctrl_dhcp4_srv.cc @@ -930,7 +930,7 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) { cfg_db->createManagers(); // Reset counters related to connections as all managers have been recreated. srv->getNetworkState()->reset(NetworkState::Origin::DB_CONNECTION); - CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->initAllocatorsAfterConfigure(); + } catch (const std::exception& ex) { err << "Unable to open database: " << ex.what(); return (isc::config::createAnswer(CONTROL_RESULT_ERROR, err.str())); @@ -1083,6 +1083,17 @@ ControlledDhcpv4Srv::finishConfigHookLibraries(isc::data::ConstElementPtr config } return (ConstElementPtr()); + } + + // Initialize the allocators. If the user selected a Free Lease Queue Allocator + // for any of the subnets, the server will now populate free leases to the queue. + // It may take a while! + try { + CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->initAllocatorsAfterConfigure(); + + } catch (const std::exception& ex) { + err << "Error initializing the lease allocators: " + << ex.what(); } isc::data::ConstElementPtr diff --git a/src/bin/dhcp6/ctrl_dhcp6_srv.cc b/src/bin/dhcp6/ctrl_dhcp6_srv.cc index 710bd18ad2..f5702ed23a 100644 --- a/src/bin/dhcp6/ctrl_dhcp6_srv.cc +++ b/src/bin/dhcp6/ctrl_dhcp6_srv.cc @@ -1102,6 +1102,16 @@ ControlledDhcpv6Srv::finishConfigHookLibraries(isc::data::ConstElementPtr config } return (ConstElementPtr()); + // Initialize the allocators. If the user selected a Free Lease Queue Allocator + // for any of the subnets, the server will now populate free leases to the queue. + // It may take a while! + try { + CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->initAllocatorsAfterConfigure(); + + } catch (const std::exception& ex) { + err << "Error initializing the lease allocators: " << ex.what(); + } + } isc::data::ConstElementPtr diff --git a/src/lib/dhcpsrv/dhcpsrv_messages.mes b/src/lib/dhcpsrv/dhcpsrv_messages.mes index 70612e983d..3dd04687f5 100644 --- a/src/lib/dhcpsrv/dhcpsrv_messages.mes +++ b/src/lib/dhcpsrv/dhcpsrv_messages.mes @@ -81,6 +81,24 @@ server configuration. The argument identifies the removed subnet. This debug message is issued when a subnet is successfully removed from the server configuration. The argument identifies the removed subnet. +% DHCPSRV_CFGMGR_FLQ_POPULATE_FREE_ADDRESS_LEASES populating free address leases for the FLQ allocator in subnet %1; it can take a while! +This informational message is issued when the server begins building a queue +of free address leases for the given subnet. It can take a considerable amount +of time, depending on the size of the address pools. + +% DHCPSRV_CFGMGR_FLQ_POPULATE_FREE_ADDRESS_LEASES_DONE populating free address leases for the FLQ allocator in subnet %1 completed +This informational message is issued when the server ends building a queue +of free address leases for a given subnet. + +% DHCPSRV_CFGMGR_FLQ_POPULATE_FREE_PREFIX_LEASES populating free prefix leases for the FLQ allocator in subnet %1; it can take a while! +This informational message is issued when the server begins building a queue +of free leases for the given subnet. It can take a considerable amount of +time, depending on the size of the delegated prefix pools. + +% DHCPSRV_CFGMGR_FLQ_POPULATE_FREE_PREFIX_LEASES_DONE populating free prefix leases for the FLQ allocator in subnet %1 completed +This informational message is issued when the server ends building a queue +of free prefix leases for a given subnet. + % DHCPSRV_CFGMGR_IPV4_RESERVATIONS_NON_UNIQUE_IGNORED ignoring "ip-reservations-unique" setting because at least one of the host database backends does not support non-unique IP reservations in a subnet This warning message is issued when the server failed to use the new setting of the ip-reservations-unique global parameter configured via the configuration diff --git a/src/lib/dhcpsrv/flq_allocator.cc b/src/lib/dhcpsrv/flq_allocator.cc index 633ac31aee..8a5535124c 100644 --- a/src/lib/dhcpsrv/flq_allocator.cc +++ b/src/lib/dhcpsrv/flq_allocator.cc @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -179,6 +180,10 @@ FreeLeaseQueueAllocator::initAfterConfigure() { template void FreeLeaseQueueAllocator::populateFreeAddressLeases(const LeaseCollectionType& leases, const PoolCollection& pools) { + auto subnet = subnet_.lock(); + LOG_INFO(dhcpsrv_logger, DHCPSRV_CFGMGR_FLQ_POPULATE_FREE_ADDRESS_LEASES) + .arg(subnet->toText()); + // Let's iterate over the lease queue and index them with the // unordered_set. Also, elminate the expired leases and those // in the expired-reclaimed state. @@ -206,10 +211,16 @@ FreeLeaseQueueAllocator::populateFreeAddressLeases(const LeaseCollectionType& le } } } + LOG_INFO(dhcpsrv_logger, DHCPSRV_CFGMGR_FLQ_POPULATE_FREE_ADDRESS_LEASES_DONE) + .arg(subnet->toText()); } void FreeLeaseQueueAllocator::populateFreePrefixDelegationLeases(const Lease6Collection& leases, const PoolCollection& pools) { + auto subnet = subnet_.lock(); + LOG_INFO(dhcpsrv_logger, DHCPSRV_CFGMGR_FLQ_POPULATE_FREE_PREFIX_LEASES) + .arg(subnet->toText()); + // Let's iterate over the lease queue and index them with the // unordered_set. Also, elminate the expired leases and those // in the expired-reclaimed state. @@ -241,6 +252,8 @@ FreeLeaseQueueAllocator::populateFreePrefixDelegationLeases(const Lease6Collecti } } } + LOG_INFO(dhcpsrv_logger, DHCPSRV_CFGMGR_FLQ_POPULATE_FREE_PREFIX_LEASES_DONE) + .arg(subnet->toText()); } SubnetFreeLeaseQueueAllocationStatePtr diff --git a/src/lib/dhcpsrv/parsers/base_network_parser.cc b/src/lib/dhcpsrv/parsers/base_network_parser.cc index e75abeed29..d5a21b26e8 100644 --- a/src/lib/dhcpsrv/parsers/base_network_parser.cc +++ b/src/lib/dhcpsrv/parsers/base_network_parser.cc @@ -281,9 +281,10 @@ BaseNetworkParser::parseAllocatorParams(const data::ConstElementPtr& network_dat NetworkPtr& network) { if (network_data->contains("allocator")) { auto allocator_type = getString(network_data, "allocator"); - if ((allocator_type != "iterative") && (allocator_type != "random")) { + if ((allocator_type != "iterative") && (allocator_type != "random") && + (allocator_type != "flq")) { // Unsupported allocator type used. - isc_throw(DhcpConfigError, "supported allocators are: iterative and random"); + isc_throw(DhcpConfigError, "supported allocators are: iterative, random and flq"); } network->setAllocatorType(allocator_type); } @@ -294,9 +295,10 @@ BaseNetworkParser::parsePdAllocatorParams(const data::ConstElementPtr& network_d Network6Ptr& network) { if (network_data->contains("pd-allocator")) { auto allocator_type = getString(network_data, "pd-allocator"); - if ((allocator_type != "iterative") && (allocator_type != "random")) { + if ((allocator_type != "iterative") && (allocator_type != "random") && + (allocator_type != "flq")) { // Unsupported allocator type used. - isc_throw(DhcpConfigError, "supported allocators are: iterative and random"); + isc_throw(DhcpConfigError, "supported allocators are: iterative, random and flq"); } network->setPdAllocatorType(allocator_type); } diff --git a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc index 6053d722c3..c5ffd3e1f7 100644 --- a/src/lib/dhcpsrv/parsers/dhcp_parsers.cc +++ b/src/lib/dhcpsrv/parsers/dhcp_parsers.cc @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include #include @@ -726,14 +728,22 @@ Subnet4ConfigParser::parse(ConstElementPtr subnet) { if (sn4ptr->getAllocatorType() == "random") { sn4ptr->setAllocator(Lease::TYPE_V4, - boost::make_shared - (Lease::TYPE_V4, sn4ptr)); + 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)); @@ -1273,25 +1283,32 @@ Subnet6ConfigParser::parse(ConstElementPtr subnet) { 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)); + 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_V4: case Lease::TYPE_NA: case Lease::TYPE_TA: if (sn6ptr->getAllocatorType() == "random") { pool->setAllocationState(PoolRandomAllocationState::create(pool)); + } else { pool->setAllocationState(PoolIterativeAllocationState::create(pool)); } @@ -1299,10 +1316,16 @@ Subnet6ConfigParser::parse(ConstElementPtr subnet) { 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; } } diff --git a/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc b/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc index 50b05b3c5d..c9dfa44ea6 100644 --- a/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc +++ b/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include #include @@ -3238,6 +3240,34 @@ TEST_F(ParseConfigTest, randomSubnetAllocator4) { EXPECT_TRUE(boost::dynamic_pointer_cast(allocator)); } +// This test verifies that Free Lease Queue allocator can be selected for +// a subnet. +TEST_F(ParseConfigTest, flqSubnetAllocator4) { + std::string config = + "{" + " \"subnet4\": [ {" + " \"subnet\": \"192.0.2.0/24\"," + " \"id\": 1," + " \"allocator\": \"flq\"" + " } ]" + "}"; + + ElementPtr json = Element::fromJSON(config); + EXPECT_TRUE(json); + ConstElementPtr status = parseElementSet(json, false); + int rcode = 0; + ConstElementPtr comment = parseAnswer(rcode, status); + ASSERT_EQ(0, rcode); + + auto subnet = CfgMgr::instance().getStagingCfg()->getCfgSubnets4()->getBySubnetId(1); + ASSERT_TRUE(subnet); + + EXPECT_EQ("flq", subnet->getAllocatorType().get()); + auto allocator = subnet->getAllocator(Lease::TYPE_V4); + ASSERT_TRUE(allocator); + EXPECT_TRUE(boost::dynamic_pointer_cast(allocator)); +} + // This test verifies that unknown allocator is rejected. TEST_F(ParseConfigTest, invalidSubnetAllocator4) { std::string config = @@ -3258,7 +3288,7 @@ TEST_F(ParseConfigTest, invalidSubnetAllocator4) { ASSERT_EQ(comment->getType(), Element::string); EXPECT_EQ(1, rcode); std::string expected = "Configuration parsing failed: "; - expected += "supported allocators are: iterative and random"; + expected += "supported allocators are: iterative, random and flq"; EXPECT_EQ(expected, comment->stringValue()); } @@ -3297,6 +3327,31 @@ TEST_F(ParseConfigTest, randomSubnetAllocator6) { EXPECT_TRUE(boost::dynamic_pointer_cast(allocator)); } +// This test verifies that FLQ allocator is not supported for +// IPv6 address pools. +TEST_F(ParseConfigTest, flqSubnetAllocator6) { + std::string config = + "{" + " \"subnet6\": [ {" + " \"subnet\": \"2001:db8:1::/64\"," + " \"id\": 1," + " \"allocator\": \"flq\"" + " } ]" + "}"; + + ElementPtr json = Element::fromJSON(config); + EXPECT_TRUE(json); + ConstElementPtr status = parseElementSet(json, false); + int rcode = 0; + ConstElementPtr comment = parseAnswer(rcode, status); + ASSERT_TRUE(comment); + ASSERT_EQ(comment->getType(), Element::string); + EXPECT_EQ(1, rcode); + std::string expected = "Configuration parsing failed: "; + expected += "Free Lease Queue allocator is not supported for IPv6 address pools"; + EXPECT_EQ(expected, comment->stringValue()); +} + // This test verifies that unknown allocator is rejected. TEST_F(ParseConfigTest, invalidSubnetAllocator6) { std::string config = @@ -3317,7 +3372,7 @@ TEST_F(ParseConfigTest, invalidSubnetAllocator6) { ASSERT_EQ(comment->getType(), Element::string); EXPECT_EQ(1, rcode); std::string expected = "Configuration parsing failed: "; - expected += "supported allocators are: iterative and random"; + expected += "supported allocators are: iterative, random and flq"; EXPECT_EQ(expected, comment->stringValue()); } @@ -3378,7 +3433,7 @@ TEST_F(ParseConfigTest, invalidSubnetPdAllocator6) { ASSERT_EQ(comment->getType(), Element::string); EXPECT_EQ(1, rcode); std::string expected = "Configuration parsing failed: "; - expected += "supported allocators are: iterative and random"; + expected += "supported allocators are: iterative, random and flq"; EXPECT_EQ(expected, comment->stringValue()); } -- 2.47.2