From: Marcin Siodelski Date: Thu, 28 Sep 2017 13:41:25 +0000 (+0200) Subject: [5364] Unit tests for shared networks now verify leases on the server. X-Git-Tag: trac5297_base~6^2~13 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bc88d6be4d619efccbc9325ec3dc989650439423;p=thirdparty%2Fkea.git [5364] Unit tests for shared networks now verify leases on the server. --- diff --git a/src/bin/dhcp4/tests/shared_network_unittest.cc b/src/bin/dhcp4/tests/shared_network_unittest.cc index 7ebb216cdc..31c0d59868 100644 --- a/src/bin/dhcp4/tests/shared_network_unittest.cc +++ b/src/bin/dhcp4/tests/shared_network_unittest.cc @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -844,6 +845,9 @@ public: EXPECT_EQ((ack ? DHCPACK : DHCPNAK), resp->getType()); if (ack) { EXPECT_EQ(exp_addr, resp->getYiaddr().toText()); + Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(IOAddress(resp->getYiaddr())); + ASSERT_TRUE(lease); + } else { EXPECT_EQ("0.0.0.0", resp->getYiaddr().toText()); } @@ -902,6 +906,8 @@ public: } else { EXPECT_EQ(DHCPACK, resp->getType()); EXPECT_EQ(exp_addr, resp->getYiaddr().toText()); + Lease4Ptr lease = LeaseMgrFactory::instance().getLease4(IOAddress(resp->getYiaddr())); + ASSERT_TRUE(lease); } } diff --git a/src/bin/dhcp6/tests/dhcp6_client.cc b/src/bin/dhcp6/tests/dhcp6_client.cc index dafb8391e4..61cc51fe74 100644 --- a/src/bin/dhcp6/tests/dhcp6_client.cc +++ b/src/bin/dhcp6/tests/dhcp6_client.cc @@ -943,6 +943,12 @@ Dhcp6Client::addExtraOption(const OptionPtr& opt) { extra_options_.insert(std::make_pair(opt->getType(), opt)); } +void +Dhcp6Client::clearExtraOptions() { + extra_options_.clear(); +} + + } // end of namespace isc::dhcp::test } // end of namespace isc::dhcp } // end of namespace isc diff --git a/src/bin/dhcp6/tests/dhcp6_client.h b/src/bin/dhcp6/tests/dhcp6_client.h index d9a4ed9e78..4d957dc934 100644 --- a/src/bin/dhcp6/tests/dhcp6_client.h +++ b/src/bin/dhcp6/tests/dhcp6_client.h @@ -741,6 +741,9 @@ public: /// @param opt additional option to be sent void addExtraOption(const OptionPtr& opt); + /// @brief Configures the client to not send any extra options. + void clearExtraOptions(); + private: /// @brief Applies the new leases for the client. diff --git a/src/bin/dhcp6/tests/shared_network_unittest.cc b/src/bin/dhcp6/tests/shared_network_unittest.cc index 9beb255f56..04359b9fbc 100644 --- a/src/bin/dhcp6/tests/shared_network_unittest.cc +++ b/src/bin/dhcp6/tests/shared_network_unittest.cc @@ -698,6 +698,49 @@ const char* NETWORKS_CONFIG[] = { " ]" " }" " ]" + "}", + +// Configuration #12. + "{" + " \"interfaces-config\": {" + " \"interfaces\": [ \"*\" ]" + " }," + " \"preferred-lifetime\": 3000," + " \"rebind-timer\": 2000, " + " \"renew-timer\": 1000, " + " \"client-classes\": [" + " {" + " \"name\": \"b-devices\"," + " \"test\": \"option[1234].hex == 0x0002\"" + " }" + " ]," + " \"shared-networks\": [" + " {" + " \"name\": \"frog\"," + " \"interface\": \"eth1\"," + " \"subnet6\": [" + " {" + " \"subnet\": \"2001:db8:1::/64\"," + " \"id\": 10," + " \"pools\": [" + " {" + " \"pool\": \"2001:db8:1::20 - 2001:db8:1::20\"" + " }" + " ]" + " }," + " {" + " \"subnet\": \"2001:db8:2::/64\"," + " \"id\": 100," + " \"pools\": [" + " {" + " \"pool\": \"2001:db8:2::20 - 2001:db8:2::20\"" + " }" + " ]," + " \"client-class\": \"b-devices\"" + " }" + " ]" + " }" + " ]" "}" }; @@ -705,6 +748,13 @@ const char* NETWORKS_CONFIG[] = { class Dhcpv6SharedNetworkTest : public Dhcpv6SrvTest { public: + /// @brief Indicates how test functions should check presence of a lease on + /// the server. + enum class LeaseOnServer{ + MUST_EXIST, + MUST_NOT_EXIST, + }; + /// @brief Constructor. Dhcpv6SharedNetworkTest() : Dhcpv6SrvTest(), @@ -728,7 +778,25 @@ public: ASSERT_NO_THROW(client.requestAddress(iaid, IOAddress(hint))); } ASSERT_NO_THROW(client.doSARR()); - ASSERT_TRUE(client.hasLeaseForAddress(IOAddress(exp_addr))); + ASSERT_TRUE(hasLeaseForAddress(client, IOAddress(exp_addr))); + } + + /// @brief Check if client has a lease for the specified address. + /// + /// Apart from checking whether the client has got the lease it also + /// checks whether this lease is stored in the lease database. + /// + /// @param client Reference to the client. + /// @param address Leased address. + /// + /// @return true if the lease for the client has been found both in the + /// database and in the server's response. + bool hasLeaseForAddress(Dhcp6Client& client, const IOAddress& address, + const LeaseOnServer& lease_on_server = LeaseOnServer::MUST_EXIST) { + Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, address); + return ((((lease_on_server == LeaseOnServer::MUST_EXIST) && lease) || + ((lease_on_server == LeaseOnServer::MUST_NOT_EXIST) && !lease)) && + client.hasLeaseForAddress(address)); } /// @brief Destructor. @@ -751,13 +819,17 @@ TEST_F(Dhcpv6SharedNetworkTest, addressPoolInSharedNetworkShortage) { ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[0], *client1.getServer())); // Client #1 requests an address in first subnet within a shared network. - doSARR(client1, "2001:db8:1::20", 0xabca, "2001:db8:1::20"); + ASSERT_NO_THROW(client1.requestAddress(0xabca0, IOAddress("2001:db8:1::20"))); + ASSERT_NO_THROW(client1.doSARR()); + ASSERT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:1::20"))); // Client #2 The second client will request a lease and should be assigned // an address from the second subnet. Dhcp6Client client2(client1.getServer()); client2.setInterface("eth1"); - doSARR(client2, "2001:db8:2::20", 0xabca0, ""); + ASSERT_NO_THROW(client2.requestAddress(0xabca0)); + ASSERT_NO_THROW(client2.doSARR()); + ASSERT_TRUE(hasLeaseForAddress(client2, IOAddress("2001:db8:2::20"))); // Cient #3. It sends Solicit which should result in NoAddrsAvail status // code because all addresses available for this link have been assigned. @@ -775,12 +847,12 @@ TEST_F(Dhcpv6SharedNetworkTest, addressPoolInSharedNetworkShortage) { // Client #1 should be able to renew its lease. ASSERT_NO_THROW(client1.doRenew()); EXPECT_EQ(1, client1.getLeaseNum()); - EXPECT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::20"))); + EXPECT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:1::20"))); // Client #2 should be able to renew its lease too. ASSERT_NO_THROW(client2.doRenew()); EXPECT_EQ(1, client2.getLeaseNum()); - EXPECT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:2::20"))); + EXPECT_TRUE(hasLeaseForAddress(client2, IOAddress("2001:db8:2::20"))); } // Shared network is selected based on relay link address. @@ -795,7 +867,9 @@ TEST_F(Dhcpv6SharedNetworkTest, sharedNetworkSelectedByRelay) { ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[1], *client1.getServer())); // Client #1 should be assigned an address from shared network. - doSARR(client1, "2001:db8:1::20", 0xabca, ""); + ASSERT_NO_THROW(client1.requestAddress(0xabca0)); + ASSERT_NO_THROW(client1.doSARR()); + ASSERT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:1::20"))); // Create client #2. This is a relayed client which is using relay // address matching subnet outside of the shared network. @@ -803,7 +877,7 @@ TEST_F(Dhcpv6SharedNetworkTest, sharedNetworkSelectedByRelay) { client2.useRelay(true, IOAddress("3001::2")); ASSERT_NO_THROW(client2.requestAddress(0xabca0)); ASSERT_NO_THROW(client2.doSARR()); - ASSERT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:2::20"))); + ASSERT_TRUE(hasLeaseForAddress(client2, IOAddress("2001:db8:2::20"))); } // Providing a hint for any address belonging to a shared network. @@ -820,14 +894,16 @@ TEST_F(Dhcpv6SharedNetworkTest, hintWithinSharedNetwork) { // should be offered out of this subnet. ASSERT_NO_THROW(client.requestAddress(0xabca, IOAddress("2001:db8:1::20"))); ASSERT_NO_THROW(client.doSolicit(true)); - ASSERT_TRUE(client.hasLeaseForAddress(IOAddress("2001:db8:1::20"))); + ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:1::20"), + LeaseOnServer::MUST_NOT_EXIST)); // Similarly, we should be offerred an address from another subnet within // the same shared network when we ask for it. client.clearRequestedIAs(); ASSERT_NO_THROW(client.requestAddress(0xabca, IOAddress("2001:db8:2::20"))); ASSERT_NO_THROW(client.doSolicit(true)); - ASSERT_TRUE(client.hasLeaseForAddress(IOAddress("2001:db8:2::20"))); + ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:2::20"), + LeaseOnServer::MUST_NOT_EXIST)); // Asking for an address that is not in address pool should result in getting // an address from one of the subnets, but generally hard to tell from which one. @@ -836,8 +912,10 @@ TEST_F(Dhcpv6SharedNetworkTest, hintWithinSharedNetwork) { ASSERT_NO_THROW(client.doSolicit(true)); std::vector leases = client.getLeasesByType(Lease::TYPE_NA); ASSERT_EQ(1, leases.size()); - if (!client.hasLeaseForAddress(IOAddress("2001:db8:1::20")) && - !client.hasLeaseForAddress(IOAddress("2001:db8:2::20"))) { + if (!hasLeaseForAddress(client, IOAddress("2001:db8:1::20"), + LeaseOnServer::MUST_NOT_EXIST) && + !hasLeaseForAddress(client, IOAddress("2001:db8:2::20"), + LeaseOnServer::MUST_NOT_EXIST)) { ADD_FAILURE() << "Unexpected address advertised by the server " << leases.at(0).addr_; } } @@ -856,7 +934,7 @@ TEST_F(Dhcpv6SharedNetworkTest, subnetInSharedNetworkSelectedByClass) { // this address because the client doesn't belong to a certain class. ASSERT_NO_THROW(client1.requestAddress(0xabca, IOAddress("2001:db8:1::20"))); ASSERT_NO_THROW(client1.doSARR()); - ASSERT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:2::20"))); + ASSERT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:2::20"))); // Release the lease that the client has got, because we'll need this address // further in the test. @@ -868,7 +946,7 @@ TEST_F(Dhcpv6SharedNetworkTest, subnetInSharedNetworkSelectedByClass) { // This time, the allocation of the address provided as hint should be successful. ASSERT_NO_THROW(client1.doSARR()); - ASSERT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::20"))); + ASSERT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:1::20"))); // Client 2 should be assigned an address from the unrestricted subnet. @@ -876,7 +954,7 @@ TEST_F(Dhcpv6SharedNetworkTest, subnetInSharedNetworkSelectedByClass) { client2.setInterface("eth1"); ASSERT_NO_THROW(client2.requestAddress(0xabca0)); ASSERT_NO_THROW(client2.doSARR()); - ASSERT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:2::20"))); + ASSERT_TRUE(hasLeaseForAddress(client2, IOAddress("2001:db8:2::20"))); // Now, let's reconfigure the server to also apply restrictions on the // subnet to which client2 now belongs. @@ -908,7 +986,7 @@ TEST_F(Dhcpv6SharedNetworkTest, reservationInSharedNetwork) { // Client #1 should get his reserved address from the second subnet. ASSERT_NO_THROW(client1.requestAddress(0xabca, IOAddress("2001:db8:1::20"))); ASSERT_NO_THROW(client1.doSARR()); - ASSERT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:2::28"))); + ASSERT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:2::28"))); // Create client #2. Dhcp6Client client2; @@ -918,7 +996,7 @@ TEST_F(Dhcpv6SharedNetworkTest, reservationInSharedNetwork) { // Client #2 should get its reserved address from the first subnet. ASSERT_NO_THROW(client2.requestAddress(0xabca, IOAddress("2001:db8:1::30"))); ASSERT_NO_THROW(client2.doSARR()); - ASSERT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:1::28"))); + ASSERT_TRUE(hasLeaseForAddress(client2, IOAddress("2001:db8:1::28"))); // Reconfigure the server. Now, the first client get's second client's // reservation and vice versa. @@ -930,7 +1008,7 @@ TEST_F(Dhcpv6SharedNetworkTest, reservationInSharedNetwork) { // this lease. ASSERT_NO_THROW(client1.doRenew()); ASSERT_TRUE(client1.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:2::28"))); - ASSERT_FALSE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::28"))); + ASSERT_FALSE(hasLeaseForAddress(client1, IOAddress("2001:db8:1::28"))); // The client should be allocated a lease from one of the dynamic pools. if (!client1.hasLeaseForAddressRange(IOAddress("2001:db8:2::1"), IOAddress("2001:db8:2::64")) && @@ -941,11 +1019,11 @@ TEST_F(Dhcpv6SharedNetworkTest, reservationInSharedNetwork) { // Client #2 is now renewing its lease and should get its newly reserved address. ASSERT_NO_THROW(client2.doRenew()); ASSERT_TRUE(client2.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:1::28"))); - ASSERT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:2::28"))); + ASSERT_TRUE(hasLeaseForAddress(client2, IOAddress("2001:db8:2::28"))); // Same for client #1. ASSERT_NO_THROW(client1.doRenew()); - ASSERT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::28"))); + ASSERT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:1::28"))); } // Reserved address can't be assigned as long as access to a subnet is @@ -965,7 +1043,7 @@ TEST_F(Dhcpv6SharedNetworkTest, reservationAccessRestrictedByClass) { // client doesn't belong to the "a-devices" class. ASSERT_NO_THROW(client.requestAddress(0xabca)); ASSERT_NO_THROW(client.doSARR()); - ASSERT_TRUE(client.hasLeaseForAddress(IOAddress("2001:db8:2::16"))); + ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:2::16"))); // Add option 1234 which would cause the client to be classified as "a-devices". OptionPtr option1234(new OptionUint16(Option::V6, 1234, 0x0001)); @@ -974,7 +1052,37 @@ TEST_F(Dhcpv6SharedNetworkTest, reservationAccessRestrictedByClass) { // The client should now be assigned the reserved address from the first subnet. ASSERT_NO_THROW(client.doRenew()); ASSERT_TRUE(client.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:2::16"))); - ASSERT_TRUE(client.hasLeaseForAddress(IOAddress("2001:db8:1::28"))); + ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:1::28"))); +} + +// Subnet in which the client is renewing an address is restricted by classification. +TEST_F(Dhcpv6SharedNetworkTest, renewalRestrictedByClass) { + // Create client. + Dhcp6Client client; + client.setInterface("eth1"); + + // Create server configuration with a shared network including two subnets. Access to + // the second subnet is restricted by client classification. + ASSERT_NO_FATAL_FAILURE(configure(NETWORKS_CONFIG[12], *client.getServer())); + + // Add option 1234 to cause the client to belong to the class. + OptionPtr option1234(new OptionUint16(Option::V6, 1234, 0x0002)); + client.addExtraOption(option1234); + + // Client requests an address from the second subnet which should be successful. + ASSERT_NO_THROW(client.requestAddress(0xabca, IOAddress("2001:db8:2::20"))); + ASSERT_NO_THROW(client.doSARR()); + ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:2::20"))); + + // Now remove the client from this class. + client.clearExtraOptions(); + + // The client should not be able to renew the existing lease because it is now + // prohibited by the classification. Instead, the client should get a lease from the + // unrestricted subnet. + ASSERT_NO_THROW(client.doRenew()); + ASSERT_TRUE(client.hasLeaseWithZeroLifetimeForAddress(IOAddress("2001:db8:2::20"))); + ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:1::20"))); } // Some options are specified on the shared subnet level, some on the @@ -999,7 +1107,7 @@ TEST_F(Dhcpv6SharedNetworkTest, optionsDerivation) { // Perform 4-way exchange and make sure we have been assigned address from the // subnet we wanted. ASSERT_NO_THROW(client1.doSARR()); - ASSERT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:1::20"))); + ASSERT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:1::20"))); // This option is specified on the global level. ASSERT_TRUE(client1.hasOptionWithAddress(D6O_NIS_SERVERS, "3000::20")); @@ -1029,7 +1137,7 @@ TEST_F(Dhcpv6SharedNetworkTest, optionsDerivation) { // Perform 4-way exchange and make sure we have been assigned address from the // subnet we wanted. ASSERT_NO_THROW(client2.doSARR()); - ASSERT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:2::20"))); + ASSERT_TRUE(hasLeaseForAddress(client2, IOAddress("2001:db8:2::20"))); // This option is specified on the global level. ASSERT_TRUE(client2.hasOptionWithAddress(D6O_NIS_SERVERS, "3000::20")); @@ -1054,7 +1162,7 @@ TEST_F(Dhcpv6SharedNetworkTest, optionsDerivation) { // Perform 4-way exchange and make sure we have been assigned address from the // subnet we wanted. ASSERT_NO_THROW(client3.doSARR()); - ASSERT_TRUE(client3.hasLeaseForAddress(IOAddress("3000::1"))); + ASSERT_TRUE(hasLeaseForAddress(client3, IOAddress("3000::1"))); // This option is specified on the global level. ASSERT_TRUE(client3.hasOptionWithAddress(D6O_NIS_SERVERS, "3000::20")); @@ -1079,8 +1187,8 @@ TEST_F(Dhcpv6SharedNetworkTest, sharedNetworkSelectionByInterface) { // Client #1 should be assigned an address from one of the two subnets // belonging to the first shared network. ASSERT_NO_THROW(client1.doSARR()); - if (!client1.hasLeaseForAddress(IOAddress("2001:db8:1::20")) && - !client1.hasLeaseForAddress(IOAddress("2001:db8:2::20"))) { + if (!hasLeaseForAddress(client1, IOAddress("2001:db8:1::20")) && + !hasLeaseForAddress(client1, IOAddress("2001:db8:2::20"))) { ADD_FAILURE() << "unexpected shared network selected for the client"; } @@ -1092,8 +1200,8 @@ TEST_F(Dhcpv6SharedNetworkTest, sharedNetworkSelectionByInterface) { // Client #2 should be assigned an address from one of the two subnets // belonging to the second shared network. ASSERT_NO_THROW(client2.doSARR()); - if (!client2.hasLeaseForAddress(IOAddress("2001:db8:3::20")) && - !client2.hasLeaseForAddress(IOAddress("2001:db8:4::20"))) { + if (!hasLeaseForAddress(client2, IOAddress("2001:db8:3::20")) && + !hasLeaseForAddress(client2, IOAddress("2001:db8:4::20"))) { ADD_FAILURE() << "unexpected shared network selected for the client"; } } @@ -1112,8 +1220,8 @@ TEST_F(Dhcpv6SharedNetworkTest, sharedNetworkSelectionByRelay) { // Client #1 should be assigned an address from one of the two subnets // belonging to the first shared network. ASSERT_NO_THROW(client1.doSARR()); - if (!client1.hasLeaseForAddress(IOAddress("2001:db8:1::20")) && - !client1.hasLeaseForAddress(IOAddress("2001:db8:2::20"))) { + if (!hasLeaseForAddress(client1, IOAddress("2001:db8:1::20")) && + !hasLeaseForAddress(client1, IOAddress("2001:db8:2::20"))) { ADD_FAILURE() << "unexpected shared network selected for the client"; } @@ -1125,8 +1233,8 @@ TEST_F(Dhcpv6SharedNetworkTest, sharedNetworkSelectionByRelay) { // Client #2 should be assigned an address from one of the two subnets // belonging to the second shared network. ASSERT_NO_THROW(client2.doSARR()); - if (!client2.hasLeaseForAddress(IOAddress("2001:db8:3::20")) && - !client2.hasLeaseForAddress(IOAddress("2001:db8:4::20"))) { + if (!hasLeaseForAddress(client2, IOAddress("2001:db8:3::20")) && + !hasLeaseForAddress(client2, IOAddress("2001:db8:4::20"))) { ADD_FAILURE() << "unexpected shared network selected for the client"; } } @@ -1192,7 +1300,8 @@ TEST_F(Dhcpv6SharedNetworkTest, sharedNetworkSelectedByClass) { // The client 1 should be offerred an address from the second subnet. ASSERT_NO_THROW(client1.doSolicit(true)); - ASSERT_TRUE(client1.hasLeaseForAddress(IOAddress("2001:db8:2::20"))); + ASSERT_TRUE(hasLeaseForAddress(client1, IOAddress("2001:db8:2::20"), + LeaseOnServer::MUST_NOT_EXIST)); // Create another client which will belong to a different class. Dhcp6Client client2; @@ -1205,7 +1314,8 @@ TEST_F(Dhcpv6SharedNetworkTest, sharedNetworkSelectedByClass) { // Client 2 should be offerred an address from the first subnet. ASSERT_NO_THROW(client2.doSolicit(true)); - ASSERT_TRUE(client2.hasLeaseForAddress(IOAddress("2001:db8:1::20"))); + ASSERT_TRUE(hasLeaseForAddress(client2, IOAddress("2001:db8:1::20"), + LeaseOnServer::MUST_NOT_EXIST)); } // Client requests two addresses and two prefixes and obtains them from two @@ -1227,16 +1337,16 @@ TEST_F(Dhcpv6SharedNetworkTest, assignmentsFromDifferentSubnets) { // 4-way exchange. ASSERT_NO_THROW(client.doSARR()); // The two addresses should come from different subnets. - ASSERT_TRUE(client.hasLeaseForAddress(IOAddress("2001:db8:1::20"))); - ASSERT_TRUE(client.hasLeaseForAddress(IOAddress("2001:db8:2::20"))); + ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:1::20"))); + ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:2::20"))); // Same for prefixes. ASSERT_TRUE(client.hasLeaseForPrefixPool(IOAddress("4000::"), 96, 96)); ASSERT_TRUE(client.hasLeaseForPrefixPool(IOAddress("5000::"), 96, 96)); // Try to renew. ASSERT_NO_THROW(client.doRenew()); - ASSERT_TRUE(client.hasLeaseForAddress(IOAddress("2001:db8:1::20"))); - ASSERT_TRUE(client.hasLeaseForAddress(IOAddress("2001:db8:2::20"))); + ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:1::20"))); + ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:2::20"))); ASSERT_TRUE(client.hasLeaseForPrefixPool(IOAddress("4000::"), 96, 96)); ASSERT_TRUE(client.hasLeaseForPrefixPool(IOAddress("5000::"), 96, 96)); } @@ -1264,7 +1374,7 @@ TEST_F(Dhcpv6SharedNetworkTest, reservedAddressAndPrefix) { ASSERT_NO_THROW(client.doSARR()); ASSERT_EQ(4, client.getLeaseNum()); // The client should have got one reserved address and one reserved prefix. - ASSERT_TRUE(client.hasLeaseForAddress(IOAddress("2001:db8:2::28"))); + ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:2::28"))); ASSERT_TRUE(client.hasLeaseForPrefix(IOAddress("1234::"), 64, IAID(0x1111))); // The client should have got dynamically allocated address too and it must be @@ -1281,7 +1391,7 @@ TEST_F(Dhcpv6SharedNetworkTest, reservedAddressAndPrefix) { // Try to renew and check this again. ASSERT_NO_THROW(client.doRenew()); ASSERT_EQ(4, client.getLeaseNum()); - ASSERT_TRUE(client.hasLeaseForAddress(IOAddress("2001:db8:2::28"))); + ASSERT_TRUE(hasLeaseForAddress(client, IOAddress("2001:db8:2::28"))); ASSERT_TRUE(client.hasLeaseForPrefix(IOAddress("1234::"), 64, IAID(0x1111))); leases_1234 = client.getLeasesByIAID(0x1234); diff --git a/src/lib/dhcpsrv/alloc_engine.cc b/src/lib/dhcpsrv/alloc_engine.cc index d4f0141f9a..fa4befed1b 100644 --- a/src/lib/dhcpsrv/alloc_engine.cc +++ b/src/lib/dhcpsrv/alloc_engine.cc @@ -1508,9 +1508,25 @@ AllocEngine::extendLease6(ClientContext6& ctx, Lease6Ptr lease) { return; } - // Check if the lease still belongs to the subnet. If it doesn't, - // we'll need to remove it. - if ((lease->type_ != Lease::TYPE_PD) && !ctx.subnet_->inRange(lease->addr_)) { + // It is likely that the lease for which we're extending the lifetime doesn't + // belong to the current but a sibling subnet. + if (ctx.subnet_->getID() != lease->subnet_id_) { + SharedNetwork6Ptr network; + ctx.subnet_->getSharedNetwork(network); + if (network) { + Subnet6Ptr subnet = network->getSubnet(SubnetID(lease->subnet_id_)); + // Found the actual subnet this lease belongs to. Stick to this + // subnet. + if (subnet) { + ctx.subnet_ = subnet; + } + } + } + + // Check if the lease still belongs to the subnet and that the use of this subnet + // is allowed per client classification. If not, remove this lease. + if (((lease->type_ != Lease::TYPE_PD) && !ctx.subnet_->inRange(lease->addr_)) || + !ctx.subnet_->clientSupported(ctx.query_->getClasses())) { // Oh dear, the lease is no longer valid. We need to get rid of it. // Remove this lease from LeaseMgr