diff --git a/ChangeLog b/ChangeLog index 273ebfaea4..4701ab7640 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2099. [func]* tmark + An address reserved in a global reservation must now lie + within the range of the subnet or shared-network selected + by Kea. In the event that it does not, the server will + attempt to allocate an address dynamically. This change + applies to both kea-dhcp4 and kea-dhcp6. Prior to this + the servers would grant a lease for any globallyo reserved + address without regard for its feasibility within the + selected subnet. + (Gitlab #2631) + 2098. [doc] razvan Updated classify ARM examples with a case when both operands of the evaluated expression are computed at runtime. diff --git a/doc/sphinx/arm/dhcp4-srv.rst b/doc/sphinx/arm/dhcp4-srv.rst index 555997c1d4..746896a787 100644 --- a/doc/sphinx/arm/dhcp4-srv.rst +++ b/doc/sphinx/arm/dhcp4-srv.rst @@ -5225,16 +5225,21 @@ every subnet that has global reservations enabled. This feature can be used to assign certain parameters, such as hostname or other dedicated, host-specific options. It can also be used to assign -addresses. However, global reservations that assign addresses bypass the -whole topology determination provided by the DHCP logic implemented in Kea. -It is very easy to misuse this feature and get a configuration that is -inconsistent. To give a specific example, imagine a global reservation -for the address 192.0.2.100 and two subnets 192.0.2.0/24 and 192.0.5.0/24. -If global reservations are used in both subnets and a device matching -global host reservations visits part of the network that is serviced by -192.0.5.0/24, it will get an IP address 192.0.2.100, a subnet 192.0.5.0, -and a default router 192.0.5.1. Obviously, such a configuration is -unusable, as the client will not be able to reach its default gateway. +addresses. + +An address assigned via global host reservation must be feasible for the +subnet the server selects for the client. In other words, the address must +lie within the subnet otherwise it will be ignored and the server will +attempt to dynamically allocate an address. In the event the selected subnet +belongs to a shared-network the server will check for feasibility against +the subnet's siblings, selecting the first in-range subnet. If no such +subnet exists, the server will fallback to dynamically allocating the address. + +.. note:: + + Prior to release 2.3.5, the server did not perform feasibility checks on + globally reserved addresses. This allowed the server to be configured to + hand out nonsensical leases for arbitrary address values. To use global host reservations, a configuration similar to the following can be used: diff --git a/doc/sphinx/arm/dhcp6-srv.rst b/doc/sphinx/arm/dhcp6-srv.rst index 7c55f4fdea..ce8a222ebb 100644 --- a/doc/sphinx/arm/dhcp6-srv.rst +++ b/doc/sphinx/arm/dhcp6-srv.rst @@ -4566,18 +4566,22 @@ every subnet that has global reservations enabled. This feature can be used to assign certain parameters, such as hostname or other dedicated, host-specific options. It can also be used to assign -addresses or prefixes. However, global reservations that assign either -of these bypass the whole topology determination provided by the DHCP logic -implemented in Kea. It is very easy to misuse this feature and get a -configuration that is inconsistent. To give a specific example, imagine -a global reservation for the address 2001:db8:1111::1 and two subnets -2001:db8:1111::/48 and 2001:db8:ffff::/48. If global reservations are -used in both subnets and a device matching global host reservations -visits part of the network that is covered by 2001:db8:ffff::/48, it -will get the IP address 2001:db8:ffff::1, which is outside of the -prefix announced by its local router using router advertisements. Such a -configuration is unusable or, at the very least, riddled with -issues, such as downlink traffic not reaching the device. +addresses or prefixes. + +An address assigned via global host reservation must be feasible for the +subnet the server selects for the client. In other words, the address must +lie within the subnet otherwise it will be ignored and the server will +attempt to dynamically allocate an address. In the event the selected subnet +belongs to a shared-network the server will check for feasibility against +the subnet's siblings, selecting the first in-range subnet. If no such +subnet exists, the server will fallback to dynamically allocating the address. +This does not apply to globally reserved prefixes. + +.. note:: + + Prior to release 2.3.5, the server did not perform feasibility checks on + globally reserved addresses. This allowed the server to be configured to + hand out nonsensical leases for arbitrary address values. To use global host reservations, a configuration similar to the following can be used: diff --git a/src/bin/dhcp4/tests/host_unittest.cc b/src/bin/dhcp4/tests/host_unittest.cc index b6774d05f3..84cb861e04 100644 --- a/src/bin/dhcp4/tests/host_unittest.cc +++ b/src/bin/dhcp4/tests/host_unittest.cc @@ -50,10 +50,15 @@ const char* CONFIGS[] = { "},\n" "{\n" " \"hw-address\": \"01:02:03:04:05:06\",\n" - " \"hostname\": \"hw-host-fixed\",\n" + " \"hostname\": \"hw-host-fixed-out-of-range\",\n" " \"ip-address\": \"192.0.1.77\"\n" "},\n" "{\n" + " \"hw-address\": \"02:02:03:04:05:06\",\n" + " \"hostname\": \"hw-host-fixed-in-range\",\n" + " \"ip-address\": \"10.0.0.77\"\n" + "},\n" + "{\n" " \"duid\": \"01:02:03:04:05\",\n" " \"hostname\": \"duid-host\"\n" "},\n" @@ -587,15 +592,24 @@ TEST_F(HostTest, globalHardwareDynamicAddress) { runDoraTest(CONFIGS[0], client, "hw-host-dynamic", "10.0.0.10"); } -// Verifies that a client matched to a global address reservation -// gets both the hostname and the reserved address -// when the subnet reservations flags are global only. -TEST_F(HostTest, globalHardwareFixedAddress) { +// Verifies that a client matched to a global in-subnet address reservation +// gets both the hostname and the reserved address when the subnet reservations +// flags are global only. +TEST_F(HostTest, globalHardwareFixedAddressInRange) { + Dhcp4Client client(Dhcp4Client::SELECTING); + + client.setHWAddress("02:02:03:04:05:06"); + runDoraTest(CONFIGS[0], client, "hw-host-fixed-in-range", "10.0.0.77"); +} + +// Verifies that a client matched to a global out-of-range address reservation +// gets the hostname and a dynmaic address when the subnet reservations +// flags are global only. +TEST_F(HostTest, globalHardwareFixedAddressOutOfRange) { Dhcp4Client client(Dhcp4Client::SELECTING); - //client.includeClientId(clientid_a); client.setHWAddress("01:02:03:04:05:06"); - runDoraTest(CONFIGS[0], client, "hw-host-fixed", "192.0.1.77"); + runDoraTest(CONFIGS[0], client, "hw-host-fixed-out-of-range", "10.0.0.10"); } // Verifies that a client can be matched to a global reservation by DUID diff --git a/src/bin/dhcp6/tests/host_unittest.cc b/src/bin/dhcp6/tests/host_unittest.cc index 5638051ea5..ea368dcf29 100644 --- a/src/bin/dhcp6/tests/host_unittest.cc +++ b/src/bin/dhcp6/tests/host_unittest.cc @@ -332,8 +332,13 @@ const char* CONFIGS[] = { "\"reservations\": [ \n" "{ \n" " \"duid\": \"01:02:03:04\", \n" - " \"hostname\": \"duid-host-fixed\", \n" - " \"ip-addresses\": [ \"3001::1\" ] \n" + " \"hostname\": \"duid-host-fixed-out-of-range\", \n" + " \"ip-addresses\": [ \"2001:db8:1::1\" ] \n" + "}, \n" + "{ \n" + " \"duid\": \"02:02:03:04\", \n" + " \"hostname\": \"duid-host-fixed-in-range\", \n" + " \"ip-addresses\": [ \"2001:db8:1::77\" ] \n" "}, \n" "{ \n" " \"duid\": \"01:02:03:05\", \n" @@ -2365,11 +2370,19 @@ TEST_F(HostTest, globalReservationsNA) { ASSERT_EQ(2, subnets->size()); { - SCOPED_TRACE("Global HR by DUID with reserved address"); + SCOPED_TRACE("Global HR by DUID with in-range reserved address"); + client.setDUID("02:02:03:04"); + client.requestAddress(1234, IOAddress("::")); + // Should get global reserved address and reserved host name + ASSERT_NO_FATAL_FAILURE(sarrTest(client, "2001:db8:1::77", "duid-host-fixed-in-range")); + } + + { + SCOPED_TRACE("Global HR by DUID with an out-of-range reserved address"); client.setDUID("01:02:03:04"); client.requestAddress(1234, IOAddress("::")); // Should get global reserved address and reserved host name - ASSERT_NO_FATAL_FAILURE(sarrTest(client, "3001::1", "duid-host-fixed")); + ASSERT_NO_FATAL_FAILURE(sarrTest(client, "2001:db8:1::1", "duid-host-fixed-out-of-range")); } { @@ -2388,7 +2401,7 @@ TEST_F(HostTest, globalReservationsNA) { client.setLinkLocal(IOAddress("fe80::3a60:77ff:fed5:ffee")); client.requestAddress(1234, IOAddress("::")); // Should get dynamic address and hardware host name - ASSERT_NO_FATAL_FAILURE(sarrTest(client, "2001:db8:1::1", "hw-host")); + ASSERT_NO_FATAL_FAILURE(sarrTest(client, "2001:db8:1::2", "hw-host")); } { diff --git a/src/lib/dhcpsrv/alloc_engine.cc b/src/lib/dhcpsrv/alloc_engine.cc index e89141b792..8d14d54748 100644 --- a/src/lib/dhcpsrv/alloc_engine.cc +++ b/src/lib/dhcpsrv/alloc_engine.cc @@ -1346,6 +1346,32 @@ AllocEngine::allocateGlobalReservedLeases6(ClientContext6& ctx, // It doesn't matter whether it is for this client or for someone else. if (!LeaseMgrFactory::instance().getLease6(ctx.currentIA().type_, addr)) { + // Check the feasibility of this address within this shared-network. + // Assign the context's subnet accordingly. + // Only necessary for IA_NA + if (type == IPv6Resrv::TYPE_NA) { + bool valid_subnet = false; + auto subnet = ctx.subnet_; + while (subnet) { + if (subnet->inRange(addr)) { + valid_subnet = true; + break; + } + + subnet = subnet->getNextSubnet(ctx.subnet_); + } + + if (!valid_subnet) { + LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, + ALLOC_ENGINE_IGNORING_UNSUITABLE_GLOBAL_ADDRESS6) + .arg(addr.toText()) + .arg(labelNetworkOrSubnet(ctx.subnet_)); + continue; + } + + ctx.subnet_ = subnet; + } + if (!ghost->getHostname().empty()) { // If there is a hostname reservation here we should stick // to this reservation. By updating the hostname in the @@ -3023,6 +3049,25 @@ void AllocEngine::reclaimLeaseInDatabase(const LeasePtrType& lease, .arg(lease->addr_.toText()); } +std::string +AllocEngine::labelNetworkOrSubnet(SubnetPtr subnet) { + if (!subnet) { + return(""); + } + + SharedNetwork4Ptr network; + subnet->getSharedNetwork(network); + std::ostringstream ss; + if (network) { + ss << "shared-network: " << network->getName(); + } else { + ss << "subnet id: " << subnet->getID(); + } + + return(ss.str()); +} + + } // namespace dhcp } // namespace isc @@ -3117,23 +3162,24 @@ hasAddressReservation(AllocEngine::ClientContext4& ctx) { return (false); } - // Flag used to perform search for global reservations only once. - bool search_global_done = false; + // Fetch the globally reserved address if there is one. + auto host = ctx.hosts_.find(SUBNET_ID_GLOBAL); + auto global_host_address = ((host != ctx.hosts_.end() && host->second) ? + host->second->getIPv4Reservation() : + IOAddress::IPV4_ZERO_ADDRESS()); + // Start with currently selected subnet. Subnet4Ptr subnet = ctx.subnet_; while (subnet) { - // Skip search if the global reservations have already been examined. - if (!search_global_done && subnet->getReservationsGlobal()) { - auto host = ctx.hosts_.find(SUBNET_ID_GLOBAL); - // if we want global + other modes we would need to - // return only if true, else continue - if (host != ctx.hosts_.end() && host->second && - !host->second->getIPv4Reservation().isV4Zero()) { - return (true); - } - // No need to perform this search again as there are no global - // reservations. - search_global_done = true; + // If there's a globally reserved address and global reservations are + // enabled for this network and we're either not enforcing address + // feasiblity or we are and it's feasible, update the selected + // network to that of the address and return true. + if (subnet->getReservationsGlobal() && + (global_host_address != IOAddress::IPV4_ZERO_ADDRESS()) && + (subnet->inRange(global_host_address))) { + ctx.subnet_ = subnet; + return (true); } if (subnet->getReservationsInSubnet()) { @@ -3158,6 +3204,13 @@ hasAddressReservation(AllocEngine::ClientContext4& ctx) { subnet = subnet->getNextSubnet(ctx.subnet_, ctx.query_->getClasses()); } + if (global_host_address != IOAddress::IPV4_ZERO_ADDRESS()) { + LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE, + ALLOC_ENGINE_IGNORING_UNSUITABLE_GLOBAL_ADDRESS) + .arg(ctx.currentHost()->getIPv4Reservation().toText()) + .arg(AllocEngine::labelNetworkOrSubnet(ctx.subnet_)); + } + return (false); } diff --git a/src/lib/dhcpsrv/alloc_engine.h b/src/lib/dhcpsrv/alloc_engine.h index 38b727e82a..5a25bde686 100644 --- a/src/lib/dhcpsrv/alloc_engine.h +++ b/src/lib/dhcpsrv/alloc_engine.h @@ -1836,6 +1836,16 @@ public: /// @brief The read-write mutex. isc::util::ReadWriteMutex rw_mutex_; + + /// @brief Generates a label for subnet or shared-network from subnet + /// + /// Creates a string for the subnet and it's ID for stand alone subnets + /// or the shared-network and its name if the given subnet belongs to a + /// shared-network. + /// + /// @param subnet pointer to the source subnet + /// @return string contaning the generated label + static std::string labelNetworkOrSubnet(SubnetPtr subnet); }; /// @brief A pointer to the @c AllocEngine object. diff --git a/src/lib/dhcpsrv/alloc_engine_messages.cc b/src/lib/dhcpsrv/alloc_engine_messages.cc index 24e8af7a9a..8b2412b65b 100644 --- a/src/lib/dhcpsrv/alloc_engine_messages.cc +++ b/src/lib/dhcpsrv/alloc_engine_messages.cc @@ -7,6 +7,8 @@ namespace isc { namespace dhcp { +extern const isc::log::MessageID ALLOC_ENGINE_IGNORING_UNSUITABLE_GLOBAL_ADDRESS = "ALLOC_ENGINE_IGNORING_UNSUITABLE_GLOBAL_ADDRESS"; +extern const isc::log::MessageID ALLOC_ENGINE_IGNORING_UNSUITABLE_GLOBAL_ADDRESS6 = "ALLOC_ENGINE_IGNORING_UNSUITABLE_GLOBAL_ADDRESS6"; extern const isc::log::MessageID ALLOC_ENGINE_LEASE_RECLAIMED = "ALLOC_ENGINE_LEASE_RECLAIMED"; extern const isc::log::MessageID ALLOC_ENGINE_REMOVAL_NCR_FAILED = "ALLOC_ENGINE_REMOVAL_NCR_FAILED"; extern const isc::log::MessageID ALLOC_ENGINE_V4_ALLOC_ERROR = "ALLOC_ENGINE_V4_ALLOC_ERROR"; @@ -90,6 +92,8 @@ extern const isc::log::MessageID ALLOC_ENGINE_V6_REVOKED_SHARED_PREFIX_LEASE = " namespace { const char* values[] = { + "ALLOC_ENGINE_IGNORING_UNSUITABLE_GLOBAL_ADDRESS", "ignoring globally reserved address %1, it falls outside %2", + "ALLOC_ENGINE_IGNORING_UNSUITABLE_GLOBAL_ADDRESS6", "ignoring globally reserved address %1, it falls outside %2", "ALLOC_ENGINE_LEASE_RECLAIMED", "successfully reclaimed lease %1", "ALLOC_ENGINE_REMOVAL_NCR_FAILED", "sending removal name change request failed for lease %1: %2", "ALLOC_ENGINE_V4_ALLOC_ERROR", "%1: error during attempt to allocate an IPv4 address: %2", diff --git a/src/lib/dhcpsrv/alloc_engine_messages.h b/src/lib/dhcpsrv/alloc_engine_messages.h index d4ce8882ea..866ce92b33 100644 --- a/src/lib/dhcpsrv/alloc_engine_messages.h +++ b/src/lib/dhcpsrv/alloc_engine_messages.h @@ -8,6 +8,8 @@ namespace isc { namespace dhcp { +extern const isc::log::MessageID ALLOC_ENGINE_IGNORING_UNSUITABLE_GLOBAL_ADDRESS; +extern const isc::log::MessageID ALLOC_ENGINE_IGNORING_UNSUITABLE_GLOBAL_ADDRESS6; extern const isc::log::MessageID ALLOC_ENGINE_LEASE_RECLAIMED; extern const isc::log::MessageID ALLOC_ENGINE_REMOVAL_NCR_FAILED; extern const isc::log::MessageID ALLOC_ENGINE_V4_ALLOC_ERROR; diff --git a/src/lib/dhcpsrv/alloc_engine_messages.mes b/src/lib/dhcpsrv/alloc_engine_messages.mes index 4e00f6c0bb..3716f49905 100644 --- a/src/lib/dhcpsrv/alloc_engine_messages.mes +++ b/src/lib/dhcpsrv/alloc_engine_messages.mes @@ -606,3 +606,15 @@ normal occurrence during conflict resolution, which can occur in cases such as the system administrator adding reservations for an address that is currently in use by another client. The server will fully recover from this situation, but clients will change their prefixes. + +% ALLOC_ENGINE_IGNORING_UNSUITABLE_GLOBAL_ADDRESS ignoring globally reserved address %1, it falls outside %2 +This debug message is issued when the allocation engine determines that +the globally reserved address falls outside the selected subnet or +shared-network. The server should ignore the reserved address and +attempt a dynamic allocation. + +% ALLOC_ENGINE_IGNORING_UNSUITABLE_GLOBAL_ADDRESS6 ignoring globally reserved address %1, it falls outside %2 +This debug message is issued when the allocation engine determines that +the globally reserved address falls outside the selected subnet or +shared-network. The server should ignore the reserved address and +attempt a dynamic allocation. diff --git a/src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc b/src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc index 9686cd68ea..c196e338d8 100644 --- a/src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc +++ b/src/lib/dhcpsrv/tests/alloc_engine4_unittest.cc @@ -1174,6 +1174,54 @@ TEST_F(SharedNetworkAlloc4Test, discoverSharedNetworkPoolClassification) { EXPECT_EQ("192.0.2.17", lease->addr_.toText()); } +// Test that global reservations within shared network take precedence over the +// existing leases regardless in which subnet belonging to a shared network +// reservations belong. +TEST_F(SharedNetworkAlloc4Test, discoverSharedNetworkReservationsGlobal) { + + EXPECT_FALSE(HostMgr::instance().getDisableSingleQuery()); + + // Create reservation for the client. + HostPtr host(new Host(&hwaddr_->hwaddr_[0], hwaddr_->hwaddr_.size(), + Host::IDENT_HWADDR, SUBNET_ID_GLOBAL, + SUBNET_ID_UNUSED, IOAddress("10.1.2.105"))); + CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host); + CfgMgr::instance().commit(); + + subnet1_->setReservationsGlobal(true); + subnet1_->setReservationsInSubnet(true); + subnet2_->setReservationsGlobal(true); + subnet2_->setReservationsInSubnet(true); + + // Start allocation from subnet1. The engine should determine that the + // client has global reservations within subnet2 and should rather + // assign reserved addresses. + AllocEngine::ClientContext4 + ctx(subnet1_, ClientIdPtr(), hwaddr_, IOAddress::IPV4_ZERO_ADDRESS(), + false, false, "host.example.com.", true); + ctx.query_.reset(new Pkt4(DHCPDISCOVER, 1234)); + AllocEngine::findReservation(ctx); + Lease4Ptr lease = engine_.allocateLease4(ctx); + ASSERT_TRUE(lease); + EXPECT_EQ("10.1.2.105", lease->addr_.toText()); + EXPECT_EQ(lease->subnet_id_, subnet2_->getID()); + + // Let's create a lease for the client to make sure the lease is not + // renewed but a reserved lease is offered. + Lease4Ptr lease2(new Lease4(IOAddress("192.0.2.17"), hwaddr_, ClientIdPtr(), + 501, time(NULL), subnet1_->getID())); + lease->cltt_ = time(NULL) - 10; // Allocated 10 seconds ago + ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease2)); + ctx.subnet_ = subnet1_; + ctx.hosts_.clear(); + AllocEngine::findReservation(ctx); + lease = engine_.allocateLease4(ctx); + ASSERT_TRUE(lease); + EXPECT_EQ("10.1.2.105", lease->addr_.toText()); + EXPECT_EQ(lease->subnet_id_, subnet2_->getID()); +} + + // Test that reservations within shared network take precedence over the // existing leases regardless in which subnet belonging to a shared network // reservations belong. @@ -1184,7 +1232,7 @@ TEST_F(SharedNetworkAlloc4Test, discoverSharedNetworkReservations) { // Create reservation for the client. HostPtr host(new Host(&hwaddr_->hwaddr_[0], hwaddr_->hwaddr_.size(), Host::IDENT_HWADDR, subnet2_->getID(), - SUBNET_ID_UNUSED, IOAddress("10.2.3.23"))); + SUBNET_ID_UNUSED, IOAddress("10.1.2.105"))); CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host); CfgMgr::instance().commit(); @@ -1198,22 +1246,39 @@ TEST_F(SharedNetworkAlloc4Test, discoverSharedNetworkReservations) { AllocEngine::findReservation(ctx); Lease4Ptr lease = engine_.allocateLease4(ctx); ASSERT_TRUE(lease); - EXPECT_EQ("10.2.3.23", lease->addr_.toText()); + EXPECT_EQ("10.1.2.105", lease->addr_.toText()); + EXPECT_EQ(lease->subnet_id_, subnet2_->getID()); - // Let's create a lease for the client to make sure the lease is not - // renewed but a reserved lease is offered. + // Let's create a lease for the client in subnet1 to make sure the lease + // is not renewed but a reserved lease is offered. Lease4Ptr lease2(new Lease4(IOAddress("192.0.2.17"), hwaddr_, ClientIdPtr(), 501, time(NULL), subnet1_->getID())); - lease->cltt_ = time(NULL) - 10; // Allocated 10 seconds ago + lease2->cltt_ = time(NULL) - 10; // Allocated 10 seconds ago ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease2)); ctx.subnet_ = subnet1_; ctx.hosts_.clear(); AllocEngine::findReservation(ctx); lease = engine_.allocateLease4(ctx); ASSERT_TRUE(lease); - EXPECT_EQ("10.2.3.23", lease->addr_.toText()); + EXPECT_EQ("10.1.2.105", lease->addr_.toText()); + EXPECT_EQ(lease->subnet_id_, subnet2_->getID()); + + // Let's create a lease for the client in subnet2 to make sure the lease + // is not renewed but a reserved lease is offered. + Lease4Ptr lease3(new Lease4(IOAddress("10.1.2.55"), hwaddr_, ClientIdPtr(), + 501, time(NULL), subnet2_->getID())); + lease3->cltt_ = time(NULL) - 10; // Allocated 10 seconds ago + ASSERT_TRUE(LeaseMgrFactory::instance().addLease(lease3)); + ctx.subnet_ = subnet1_; + ctx.hosts_.clear(); + AllocEngine::findReservation(ctx); + lease = engine_.allocateLease4(ctx); + ASSERT_TRUE(lease); + EXPECT_EQ("10.1.2.105", lease->addr_.toText()); + EXPECT_EQ(lease->subnet_id_, subnet2_->getID()); } + // Test that reservations within shared network take precedence over the // existing leases regardless in which subnet belonging to a shared network // reservations belong. Host lookups returning a collection are disabled. @@ -1228,10 +1293,15 @@ TEST_F(SharedNetworkAlloc4Test, discoverSharedNetworkReservationsNoColl) { // Create reservation for the client. HostPtr host(new Host(&hwaddr_->hwaddr_[0], hwaddr_->hwaddr_.size(), Host::IDENT_HWADDR, subnet2_->getID(), - SUBNET_ID_UNUSED, IOAddress("10.2.3.23"))); + SUBNET_ID_UNUSED, IOAddress("10.1.2.105"))); CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host); CfgMgr::instance().commit(); + subnet1_->setReservationsGlobal(true); + subnet1_->setReservationsInSubnet(true); + subnet2_->setReservationsGlobal(true); + subnet2_->setReservationsInSubnet(true); + // Start allocation from subnet1. The engine should determine that the // client has reservations in subnet2 and should rather assign reserved // addresses. @@ -1242,7 +1312,8 @@ TEST_F(SharedNetworkAlloc4Test, discoverSharedNetworkReservationsNoColl) { AllocEngine::findReservation(ctx); Lease4Ptr lease = engine_.allocateLease4(ctx); ASSERT_TRUE(lease); - EXPECT_EQ("10.2.3.23", lease->addr_.toText()); + EXPECT_EQ("10.1.2.105", lease->addr_.toText()); + EXPECT_EQ(lease->subnet_id_, subnet2_->getID()); // Let's create a lease for the client to make sure the lease is not // renewed but a reserved lease is offered. @@ -1255,7 +1326,8 @@ TEST_F(SharedNetworkAlloc4Test, discoverSharedNetworkReservationsNoColl) { AllocEngine::findReservation(ctx); lease = engine_.allocateLease4(ctx); ASSERT_TRUE(lease); - EXPECT_EQ("10.2.3.23", lease->addr_.toText()); + EXPECT_EQ("10.1.2.105", lease->addr_.toText()); + EXPECT_EQ(lease->subnet_id_, subnet2_->getID()); } // This test verifies that the server can offer an address from a shared @@ -1499,7 +1571,7 @@ TEST_F(SharedNetworkAlloc4Test, requestSharedNetworkReservations) { // Create reservation for the client. HostPtr host(new Host(&hwaddr_->hwaddr_[0], hwaddr_->hwaddr_.size(), Host::IDENT_HWADDR, subnet2_->getID(), - SUBNET_ID_UNUSED, IOAddress("10.2.3.23"))); + SUBNET_ID_UNUSED, IOAddress("10.1.2.105"))); CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host); CfgMgr::instance().commit(); @@ -1513,7 +1585,8 @@ TEST_F(SharedNetworkAlloc4Test, requestSharedNetworkReservations) { AllocEngine::findReservation(ctx); Lease4Ptr lease = engine_.allocateLease4(ctx); ASSERT_TRUE(lease); - EXPECT_EQ("10.2.3.23", lease->addr_.toText()); + EXPECT_EQ("10.1.2.105", lease->addr_.toText()); + EXPECT_EQ(lease->subnet_id_, subnet2_->getID()); // Remove the lease for another test below. ASSERT_TRUE(LeaseMgrFactory::instance().deleteLease(lease)); @@ -1529,7 +1602,8 @@ TEST_F(SharedNetworkAlloc4Test, requestSharedNetworkReservations) { AllocEngine::findReservation(ctx); lease = engine_.allocateLease4(ctx); ASSERT_TRUE(lease); - EXPECT_EQ("10.2.3.23", lease->addr_.toText()); + EXPECT_EQ("10.1.2.105", lease->addr_.toText()); + EXPECT_EQ(lease->subnet_id_, subnet2_->getID()); } // Test that reservations within shared network take precedence over the @@ -1546,7 +1620,7 @@ TEST_F(SharedNetworkAlloc4Test, requestSharedNetworkReservationsNoColl) { // Create reservation for the client. HostPtr host(new Host(&hwaddr_->hwaddr_[0], hwaddr_->hwaddr_.size(), Host::IDENT_HWADDR, subnet2_->getID(), - SUBNET_ID_UNUSED, IOAddress("10.2.3.23"))); + SUBNET_ID_UNUSED, IOAddress("10.1.2.105"))); CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host); CfgMgr::instance().commit(); @@ -1560,7 +1634,8 @@ TEST_F(SharedNetworkAlloc4Test, requestSharedNetworkReservationsNoColl) { AllocEngine::findReservation(ctx); Lease4Ptr lease = engine_.allocateLease4(ctx); ASSERT_TRUE(lease); - EXPECT_EQ("10.2.3.23", lease->addr_.toText()); + EXPECT_EQ("10.1.2.105", lease->addr_.toText()); + EXPECT_EQ(lease->subnet_id_, subnet2_->getID()); // Remove the lease for another test below. ASSERT_TRUE(LeaseMgrFactory::instance().deleteLease(lease)); @@ -1576,7 +1651,8 @@ TEST_F(SharedNetworkAlloc4Test, requestSharedNetworkReservationsNoColl) { AllocEngine::findReservation(ctx); lease = engine_.allocateLease4(ctx); ASSERT_TRUE(lease); - EXPECT_EQ("10.2.3.23", lease->addr_.toText()); + EXPECT_EQ("10.1.2.105", lease->addr_.toText()); + EXPECT_EQ(lease->subnet_id_, subnet2_->getID()); } // This test checks if an expired lease can be reused in DHCPDISCOVER (fake @@ -3128,11 +3204,11 @@ TEST_F(AllocEngine4Test, reservedAddressExistingLeaseStat) { // This test checks the behavior of the allocation engine in the following // scenario: // - Client has no lease in the database. -// - Client has a global reservation. +// - Client has a global reservation outside of the subnet. // - Client sends DISCOVER -// - Client is allocated the reserved address. +// - Client is allocated an address within the subnet. // - Lease is not added to the lease database -TEST_F(AllocEngine4Test, globalReservationReservedAddressDiscover) { +TEST_F(AllocEngine4Test, globalReservationReservedNonMatchingAddressDiscover) { // Create reservation for the client. HostPtr host(new Host(&hwaddr_->hwaddr_[0], hwaddr_->hwaddr_.size(), Host::IDENT_HWADDR, SUBNET_ID_GLOBAL, @@ -3159,10 +3235,10 @@ TEST_F(AllocEngine4Test, globalReservationReservedAddressDiscover) { EXPECT_EQ(ctx.currentHost()->getHostname(), host->getHostname()); EXPECT_EQ(ctx.currentHost()->getIPv4Reservation(), host->getIPv4Reservation()); - // We should allocate the reserved address. + // We should allocate an address in the subnet Lease4Ptr lease = engine.allocateLease4(ctx); ASSERT_TRUE(lease); - EXPECT_EQ("192.0.77.123", lease->addr_.toText()); + EXPECT_TRUE(subnet_->inRange(lease->addr_)); // This is a "fake" allocation so the returned lease should not be committed // to the lease database. @@ -3176,11 +3252,59 @@ TEST_F(AllocEngine4Test, globalReservationReservedAddressDiscover) { // This test checks the behavior of the allocation engine in the following // scenario: // - Client has no lease in the database. -// - Client has a global reservation. +// - Client has a global reservation matching the current subnet. +// - Client sends DISCOVER +// - Client is allocated the reserved address. +// - Lease is not added to the lease database +TEST_F(AllocEngine4Test, globalReservationReservedMatchingAddressDiscover) { + // Create reservation for the client. + HostPtr host(new Host(&hwaddr_->hwaddr_[0], hwaddr_->hwaddr_.size(), + Host::IDENT_HWADDR, SUBNET_ID_GLOBAL, + SUBNET_ID_UNUSED, IOAddress("192.0.2.10"))); + CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host); + CfgMgr::instance().commit(); + + AllocEngine engine(0); + + subnet_->setReservationsGlobal(true); + + // Query allocation engine for the lease to be assigned to this + // client without specifying the address to be assigned. + AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_, + IOAddress("0.0.0.0"), false, false, + "", true); + ctx.query_.reset(new Pkt4(DHCPDISCOVER, 1234)); + + // Look up the host. + AllocEngine::findReservation(ctx); + + // We should have the correct current host + EXPECT_TRUE(ctx.currentHost()); + EXPECT_EQ(ctx.currentHost()->getHostname(), host->getHostname()); + EXPECT_EQ(ctx.currentHost()->getIPv4Reservation(), host->getIPv4Reservation()); + + // We should allocate the reserved address. + Lease4Ptr lease = engine.allocateLease4(ctx); + ASSERT_TRUE(lease); + EXPECT_EQ("192.0.2.10", lease->addr_.toText()); + + // This is a "fake" allocation so the returned lease should not be committed + // to the lease database. + EXPECT_FALSE(LeaseMgrFactory::instance().getLease4(lease->addr_)); + + // Client had no lease in the database, so the old lease returned should + // be NULL. + ASSERT_FALSE(ctx.old_lease_); +} + +// This test checks the behavior of the allocation engine in the following +// scenario: +// - Client has no lease in the database. +// - Client has a global reservation outside the current subnet. // - Client sends REQUEST // - Client is allocated the reserved address. // - Lease is added to the lease database -TEST_F(AllocEngine4Test, globalReservationReservedAddressRequest) { +TEST_F(AllocEngine4Test, globalReservationReservedNonMatchingAddressRequest) { // Create reservation for the client. HostPtr host(new Host(&hwaddr_->hwaddr_[0], hwaddr_->hwaddr_.size(), Host::IDENT_HWADDR, SUBNET_ID_GLOBAL, @@ -3210,7 +3334,58 @@ TEST_F(AllocEngine4Test, globalReservationReservedAddressRequest) { // We should allocate the reserved address. Lease4Ptr lease = engine.allocateLease4(ctx); ASSERT_TRUE(lease); - EXPECT_EQ("192.0.77.123", lease->addr_.toText()); + EXPECT_TRUE(subnet_->inRange(lease->addr_)); + + // Check that the lease is indeed in LeaseMgr + Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(lease->addr_); + ASSERT_TRUE(from_mgr); + + // Now check that the lease in LeaseMgr has the same parameters + detailCompareLease(lease, from_mgr); + + // Client had no lease in the database, so the old lease returned should + // be NULL. + ASSERT_FALSE(ctx.old_lease_); +} + +// This test checks the behavior of the allocation engine in the following +// scenario: +// - Client has no lease in the database. +// - Client has a global reservation matching the current subnet. +// - Client sends REQUEST +// - Client is allocated the reserved address. +// - Lease is added to the lease database +TEST_F(AllocEngine4Test, globalReservationReservedMatchingAddressRequest) { + // Create reservation for the client. + HostPtr host(new Host(&hwaddr_->hwaddr_[0], hwaddr_->hwaddr_.size(), + Host::IDENT_HWADDR, SUBNET_ID_GLOBAL, + SUBNET_ID_UNUSED, IOAddress("192.0.2.10"))); + CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host); + CfgMgr::instance().commit(); + + AllocEngine engine(0); + + subnet_->setReservationsGlobal(true); + + // Query allocation engine for the lease to be assigned to this + // client without specifying the address to be assigned. + AllocEngine::ClientContext4 ctx(subnet_, clientid_, hwaddr_, + IOAddress("0.0.0.0"), false, false, + "", false); + ctx.query_.reset(new Pkt4(DHCPREQUEST, 1234)); + + // Look up the host. + AllocEngine::findReservation(ctx); + + // We should have the correct current host + EXPECT_TRUE(ctx.currentHost()); + EXPECT_EQ(ctx.currentHost()->getHostname(), host->getHostname()); + EXPECT_EQ(ctx.currentHost()->getIPv4Reservation(), host->getIPv4Reservation()); + + // We should allocate the reserved address. + Lease4Ptr lease = engine.allocateLease4(ctx); + ASSERT_TRUE(lease); + EXPECT_EQ("192.0.2.10", lease->addr_.toText()); // Check that the lease is indeed in LeaseMgr Lease4Ptr from_mgr = LeaseMgrFactory::instance().getLease4(lease->addr_); diff --git a/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc b/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc index a5d1b065a1..b783ec508f 100644 --- a/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc +++ b/src/lib/dhcpsrv/tests/alloc_engine6_unittest.cc @@ -28,6 +28,10 @@ namespace isc { namespace dhcp { namespace test { +// Convenience values to improve readibility. +const bool IN_SUBNET = true; +const bool IN_POOL = true; + // Test convenience method adding hints to IA context. TEST(ClientContext6Test, addHint) { AllocEngine::ClientContext6 ctx; @@ -792,7 +796,7 @@ TEST_F(AllocEngine6Test, renewExtendLeaseLifetime) { hints.push_back(AllocEngine::Resource(IOAddress("2001:db8:1::15"), 128)); // Client should receive a lease. - Lease6Collection renewed = renewTest(engine, pool_, hints, true); + Lease6Collection renewed = renewTest(engine, pool_, hints, IN_SUBNET, IN_POOL); ASSERT_EQ(1, renewed.size()); // And the lease lifetime should be extended. @@ -823,7 +827,7 @@ TEST_F(AllocEngine6Test, defaultRenewLeaseLifetime) { 128, 0, 0)); // Client should receive a lease. - Lease6Collection renewed = renewTest(engine, pool_, hints, true); + Lease6Collection renewed = renewTest(engine, pool_, hints, IN_SUBNET, IN_POOL); ASSERT_EQ(1, renewed.size()); // And the lease lifetime should be extended. @@ -858,7 +862,7 @@ TEST_F(AllocEngine6Test, hintRenewLeaseLifetime) { 128, 301, 399)); // Client should receive a lease. - Lease6Collection renewed = renewTest(engine, pool_, hints, true); + Lease6Collection renewed = renewTest(engine, pool_, hints, IN_SUBNET, IN_POOL); ASSERT_EQ(1, renewed.size()); // And the lease lifetime should be extended. @@ -893,7 +897,7 @@ TEST_F(AllocEngine6Test, minRenewLeaseLifetime) { 128, 100, 200)); // Client should receive a lease. - Lease6Collection renewed = renewTest(engine, pool_, hints, true); + Lease6Collection renewed = renewTest(engine, pool_, hints, IN_SUBNET, IN_POOL); ASSERT_EQ(1, renewed.size()); // And the lease lifetime should be extended. @@ -928,7 +932,7 @@ TEST_F(AllocEngine6Test, maxRenewLeaseLifetime) { 128, 500, 600)); // Client should receive a lease. - Lease6Collection renewed = renewTest(engine, pool_, hints, true); + Lease6Collection renewed = renewTest(engine, pool_, hints, IN_SUBNET, IN_POOL); ASSERT_EQ(1, renewed.size()); // And the lease lifetime should be extended. @@ -965,7 +969,7 @@ TEST_F(AllocEngine6Test, renewExtendLeaseLifetimeForReservation) { hints.push_back(AllocEngine::Resource(IOAddress("2001:db8:1::15"), 128)); // Client should receive a lease. - Lease6Collection renewed = renewTest(engine, pool_, hints, true); + Lease6Collection renewed = renewTest(engine, pool_, hints, IN_SUBNET, IN_POOL); ASSERT_EQ(1, renewed.size()); // And the lease lifetime should be extended. @@ -1741,7 +1745,7 @@ TEST_F(AllocEngine6Test, addressRenewal) { AllocEngine::HintContainer hints; hints.push_back(AllocEngine::Resource(leases[0]->addr_, 128)); - Lease6Collection renewed = renewTest(engine, pool_, hints, true); + Lease6Collection renewed = renewTest(engine, pool_, hints, IN_SUBNET, IN_POOL); ASSERT_EQ(1, renewed.size()); // Check that the lease was indeed renewed and hasn't changed @@ -1794,7 +1798,7 @@ TEST_F(AllocEngine6Test, reservedAddressRenewal) { AllocEngine::HintContainer hints; hints.push_back(AllocEngine::Resource(leases[0]->addr_, 128)); - Lease6Collection renewed = renewTest(engine, pool_, hints, true); + Lease6Collection renewed = renewTest(engine, pool_, hints, IN_SUBNET, IN_POOL); ASSERT_EQ(1, renewed.size()); ASSERT_EQ("2001:db8:1::1c", leases[0]->addr_.toText()); @@ -1940,7 +1944,7 @@ TEST_F(AllocEngine6Test, reservedAddressRenewChange) { // as the pool is 2001:db8:1::10 - 2001:db8:1::20. createHost6(true, IPv6Resrv::TYPE_NA, IOAddress("2001:db8:1::1c"), 128); - Lease6Collection renewed = renewTest(engine, pool_, hints, true); + Lease6Collection renewed = renewTest(engine, pool_, hints, IN_SUBNET, IN_POOL); ASSERT_EQ(1, renewed.size()); ASSERT_EQ("2001:db8:1::1c", renewed[0]->addr_.toText()); } @@ -1971,7 +1975,7 @@ TEST_F(AllocEngine6Test, reservedAddressRenewReserved) { CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host); CfgMgr::instance().commit(); - Lease6Collection renewed = renewTest(engine, pool_, hints, true); + Lease6Collection renewed = renewTest(engine, pool_, hints, IN_SUBNET, IN_POOL); ASSERT_EQ(1, renewed.size()); // Check that we no longer have the reserved address. @@ -3139,7 +3143,7 @@ TEST_F(AllocEngine6Test, hostDynamicAddress) { hostname_ = "host1"; // Client should receive a lease. - Lease6Collection renewed = renewTest(*engine, pool_, hints, true); + Lease6Collection renewed = renewTest(*engine, pool_, hints, IN_SUBNET, IN_POOL); ASSERT_EQ(1, renewed.size()); Lease6Ptr renewed_lease = renewed[0]; @@ -3229,7 +3233,7 @@ TEST_F(AllocEngine6Test, globalHostDynamicAddress) { hostname_ = "ghost1"; // Client should receive a lease. - Lease6Collection renewed = renewTest(*engine, pool_, hints, true); + Lease6Collection renewed = renewTest(*engine, pool_, hints, IN_SUBNET, IN_POOL); ASSERT_EQ(1, renewed.size()); // And the lease lifetime should be extended. @@ -3302,7 +3306,70 @@ TEST_F(AllocEngine6Test, globalHostReservedAddress) { Lease6Ptr lease; ASSERT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx))); ASSERT_TRUE(lease); - EXPECT_EQ("3001::1", lease->addr_.toText()); +// EXPECT_EQ("3001::1", lease->addr_.toText()); + EXPECT_TRUE(subnet_->inRange(lease->addr_)) + << " address not in range: " << lease->addr_.toText(); + + ASSERT_NO_FATAL_FAILURE(rollbackPersistedCltt(lease)); + EXPECT_NO_THROW(LeaseMgrFactory::instance().updateLease6(lease)); + + // This is what the client will send in his renew message. + AllocEngine::HintContainer hints; + hints.push_back(AllocEngine::Resource(IOAddress(lease->addr_.toText()), 128)); + + // Set test fixture hostname_ to the expected value. This gets checked in + // renewTest. + hostname_ = "ghost1"; + + // Client should receive a lease. + Lease6Collection renewed = renewTest(*engine, pool_, hints, IN_SUBNET, IN_POOL); + ASSERT_EQ(1, renewed.size()); + + // And the lease lifetime should be extended. + EXPECT_GT(renewed[0]->cltt_, lease->cltt_) + << "Lease lifetime was not extended, but it should"; +} + +// Verifies that client with a global address reservation can get and +// renew a lease for an arbitrary address. +TEST_F(AllocEngine6Test, globalHostReservedMatchingAddress) { + boost::scoped_ptr engine; + ASSERT_NO_THROW(engine.reset(new AllocEngine(100))); + ASSERT_TRUE(engine); + + HostPtr host(new Host(&duid_->getDuid()[0], duid_->getDuid().size(), + Host::IDENT_DUID, SUBNET_ID_UNUSED, SUBNET_ID_GLOBAL, + asiolink::IOAddress("0.0.0.0"))); + host->setHostname("ghost1"); + IPv6Resrv resv(IPv6Resrv::TYPE_NA, asiolink::IOAddress("2001:db8:1::a"), 128); + host->addReservation(resv); + + CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(host); + CfgMgr::instance().commit(); + + subnet_->setReservationsGlobal(true); + + // Create context which will be used to try to allocate leases + Pkt6Ptr query(new Pkt6(DHCPV6_REQUEST, 1234)); + AllocEngine::ClientContext6 ctx(subnet_, duid_, false, false, "", false, query); + ctx.currentIA().iaid_ = iaid_; + + // Look up the reservation. + findReservation(*engine, ctx); + // Make sure we found our host. + ConstHostPtr current = ctx.currentHost(); + ASSERT_TRUE(current); + ASSERT_EQ("ghost1", current->getHostname()); + + // Check that we have been allocated the fixed address. + Lease6Ptr lease; + ASSERT_NO_THROW(lease = expectOneLease(engine->allocateLeases6(ctx))); + ASSERT_TRUE(lease); + EXPECT_EQ("2001:db8:1::a", lease->addr_.toText()); + + // We're going to rollback the clock a little so we can verify a renewal. + //--lease->cltt_; + ASSERT_NO_FATAL_FAILURE(rollbackPersistedCltt(lease)); // We're going to rollback the clock a little so we can verify a renewal. --lease->cltt_; @@ -3310,14 +3377,14 @@ TEST_F(AllocEngine6Test, globalHostReservedAddress) { // This is what the client will send in his renew message. AllocEngine::HintContainer hints; - hints.push_back(AllocEngine::Resource(IOAddress("3001::1"), 128)); + hints.push_back(AllocEngine::Resource(IOAddress("2008:db8:1::a"), 128)); // Set test fixture hostname_ to the expected value. This gets checked in // renewTest. hostname_ = "ghost1"; // Client should receive a lease. - Lease6Collection renewed = renewTest(*engine, pool_, hints, false); + Lease6Collection renewed = renewTest(*engine, pool_, hints, IN_SUBNET, !IN_POOL); ASSERT_EQ(1, renewed.size()); // And the lease lifetime should be extended. @@ -3379,7 +3446,7 @@ TEST_F(AllocEngine6Test, globalHostReservedPrefix) { Pool6Ptr dummy_pool(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8::"), 64, 64)); // Client should receive a lease. - Lease6Collection renewed = renewTest(*engine, dummy_pool, hints, false); + Lease6Collection renewed = renewTest(*engine, dummy_pool, hints, !IN_SUBNET, !IN_POOL); ASSERT_EQ(1, renewed.size()); // And the lease lifetime should be extended. @@ -3444,7 +3511,7 @@ TEST_F(AllocEngine6Test, globalHostReservedPrefixDifferentPrefixLen) { Pool6Ptr dummy_pool(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8::"), 64, 64)); // Client should receive a lease. - Lease6Collection renewed = renewTest(*engine, dummy_pool, hints, false); + Lease6Collection renewed = renewTest(*engine, dummy_pool, hints, !IN_SUBNET, !IN_POOL); ASSERT_EQ(1, renewed.size()); // And the lease lifetime should be extended. @@ -3504,7 +3571,7 @@ TEST_F(AllocEngine6Test, mixedHostReservedAddress) { hostname_ = "mhost1"; // Client should receive a lease. - Lease6Collection renewed = renewTest(*engine, pool_, hints, true); + Lease6Collection renewed = renewTest(*engine, pool_, hints, IN_SUBNET, IN_POOL); ASSERT_EQ(1, renewed.size()); // And the lease lifetime should be extended. @@ -3570,7 +3637,7 @@ TEST_F(AllocEngine6Test, mixedHostReservedPrefix) { Pool6Ptr dummy_pool(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8::"), 64, 64)); // Client should receive a lease. - Lease6Collection renewed = renewTest(*engine, dummy_pool, hints, true); + Lease6Collection renewed = renewTest(*engine, dummy_pool, hints, IN_SUBNET, IN_POOL); ASSERT_EQ(1, renewed.size()); // And the lease lifetime should be extended. @@ -3633,7 +3700,7 @@ TEST_F(AllocEngine6Test, mixedHostReservedPrefixDifferentPrefixLen) { Pool6Ptr dummy_pool(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8::"), 64, 64)); // Client should receive a lease. - Lease6Collection renewed = renewTest(*engine, dummy_pool, hints, true); + Lease6Collection renewed = renewTest(*engine, dummy_pool, hints, IN_SUBNET, IN_POOL); ASSERT_EQ(1, renewed.size()); // And the lease lifetime should be extended. @@ -3702,7 +3769,7 @@ TEST_F(AllocEngine6Test, bothHostReservedAddress) { hostname_ = "mhost1"; // Client should receive a lease. - Lease6Collection renewed = renewTest(*engine, pool_, hints, true); + Lease6Collection renewed = renewTest(*engine, pool_, hints, IN_SUBNET, IN_POOL); ASSERT_EQ(1, renewed.size()); // And the lease lifetime should be extended. @@ -3774,7 +3841,7 @@ TEST_F(AllocEngine6Test, bothHostReservedPrefix) { Pool6Ptr dummy_pool(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8::"), 64, 64)); // Client should receive a lease. - Lease6Collection renewed = renewTest(*engine, dummy_pool, hints, true); + Lease6Collection renewed = renewTest(*engine, dummy_pool, hints, IN_SUBNET, IN_POOL); ASSERT_EQ(1, renewed.size()); // And the lease lifetime should be extended. @@ -3849,7 +3916,7 @@ TEST_F(AllocEngine6Test, bothHostReservedPrefixDifferentPrefixLen) { Pool6Ptr dummy_pool(new Pool6(Lease::TYPE_PD, IOAddress("2001:db8::"), 64, 64)); // Client should receive a lease. - Lease6Collection renewed = renewTest(*engine, dummy_pool, hints, true); + Lease6Collection renewed = renewTest(*engine, dummy_pool, hints, IN_SUBNET, IN_POOL); ASSERT_EQ(1, renewed.size()); // And the lease lifetime should be extended. diff --git a/src/lib/dhcpsrv/tests/alloc_engine_utils.cc b/src/lib/dhcpsrv/tests/alloc_engine_utils.cc index f6e9637b40..86fc416b10 100644 --- a/src/lib/dhcpsrv/tests/alloc_engine_utils.cc +++ b/src/lib/dhcpsrv/tests/alloc_engine_utils.cc @@ -403,7 +403,7 @@ AllocEngine6Test::simpleAlloc6Test(const Pool6Ptr& pool, const DuidPtr& duid, Lease6Collection AllocEngine6Test::renewTest(AllocEngine& engine, const Pool6Ptr& pool, AllocEngine::HintContainer& hints, - bool in_pool) { + bool in_subnet, bool in_pool) { Lease::Type type = pool->getType(); uint8_t expected_len = pool->getLength(); @@ -421,7 +421,7 @@ AllocEngine6Test::renewTest(AllocEngine& engine, const Pool6Ptr& pool, for (Lease6Collection::iterator it = leases.begin(); it != leases.end(); ++it) { // Do all checks on the lease - checkLease6(duid_, *it, type, expected_len, in_pool, in_pool); + checkLease6(duid_, *it, type, expected_len, in_subnet, in_pool); // Check that context has been updated with allocated addresses or // prefixes. diff --git a/src/lib/dhcpsrv/tests/alloc_engine_utils.h b/src/lib/dhcpsrv/tests/alloc_engine_utils.h index 4d3b36bc80..22efed4c09 100644 --- a/src/lib/dhcpsrv/tests/alloc_engine_utils.h +++ b/src/lib/dhcpsrv/tests/alloc_engine_utils.h @@ -358,12 +358,14 @@ public: /// @param engine a reference to Allocation Engine /// @param pool pool from which the lease will be allocated from /// @param hints address to be used as a hint + /// @param in_subnet whether the lease is expected to be in subnet /// @param in_pool specifies whether the lease is expected to be in pool /// @return allocated lease(s) (may be empty) Lease6Collection renewTest(AllocEngine& engine, const Pool6Ptr& pool, AllocEngine::HintContainer& hints, - bool in_pool = true); + bool in_subnet, + bool in_pool); /// @brief Checks if the address allocation with a hint that is in range, /// in pool, but is currently used, can succeed