From 4c40c4e02510c2e3618503da557f092810a3407d Mon Sep 17 00:00:00 2001 From: Razvan Becheriu Date: Thu, 24 Jul 2025 18:32:50 +0300 Subject: [PATCH] [#3826] Implemented lease6-get-by-hw-address command. --- doc/sphinx/api-files.txt | 1 + doc/sphinx/arm/hooks-lease-cmds.rst | 6 + src/hooks/dhcp/lease_cmds/lease_cmds.cc | 28 ++- src/hooks/dhcp/lease_cmds/lease_cmds.dox | 2 +- src/hooks/dhcp/lease_cmds/lease_cmds.h | 6 +- .../dhcp/lease_cmds/lease_cmds_callouts.cc | 13 ++ .../libloadtests/lease_cmds6_unittest.cc | 168 +++++++++++++++--- .../libloadtests/lease_cmds_unittest.cc | 2 +- .../libloadtests/lease_cmds_unittest.h | 12 +- src/hooks/dhcp/mysql/mysql_lb_messages.cc | 6 +- src/hooks/dhcp/mysql/mysql_lb_messages.h | 3 +- src/hooks/dhcp/mysql/mysql_lb_messages.mes | 8 +- src/hooks/dhcp/mysql/mysql_lease_mgr.cc | 52 +++++- src/hooks/dhcp/mysql/mysql_lease_mgr.h | 19 ++ .../mysql/tests/mysql_lease_mgr_unittest.cc | 36 ++++ src/hooks/dhcp/pgsql/pgsql_lb_messages.cc | 6 +- src/hooks/dhcp/pgsql/pgsql_lb_messages.h | 3 +- src/hooks/dhcp/pgsql/pgsql_lb_messages.mes | 8 +- src/hooks/dhcp/pgsql/pgsql_lease_mgr.cc | 40 ++++- src/hooks/dhcp/pgsql/pgsql_lease_mgr.h | 16 ++ .../pgsql/tests/pgsql_lease_mgr_unittest.cc | 36 ++++ src/lib/dhcpsrv/dhcpsrv_messages.cc | 6 +- src/lib/dhcpsrv/dhcpsrv_messages.h | 3 +- src/lib/dhcpsrv/dhcpsrv_messages.mes | 8 +- src/lib/dhcpsrv/lease.cc | 4 +- src/lib/dhcpsrv/lease_mgr.h | 12 ++ src/lib/dhcpsrv/memfile_lease_mgr.cc | 34 +++- src/lib/dhcpsrv/memfile_lease_mgr.h | 19 ++ src/lib/dhcpsrv/memfile_lease_storage.h | 25 +++ .../tests/memfile_lease_mgr_unittest.cc | 29 +++ .../dhcpsrv/testutils/concrete_lease_mgr.cc | 5 + .../dhcpsrv/testutils/concrete_lease_mgr.h | 12 ++ .../testutils/generic_lease_mgr_unittest.cc | 109 +++++++++++- .../testutils/generic_lease_mgr_unittest.h | 15 ++ src/share/api/lease6-get-by-hw-address.json | 51 ++++++ 35 files changed, 746 insertions(+), 57 deletions(-) create mode 100644 src/share/api/lease6-get-by-hw-address.json diff --git a/doc/sphinx/api-files.txt b/doc/sphinx/api-files.txt index db6964b814..b8a89815da 100644 --- a/doc/sphinx/api-files.txt +++ b/doc/sphinx/api-files.txt @@ -61,6 +61,7 @@ src/share/api/lease6-del.json src/share/api/lease6-get.json src/share/api/lease6-get-all.json src/share/api/lease6-get-by-duid.json +src/share/api/lease6-get-by-hw-address.json src/share/api/lease6-get-by-hostname.json src/share/api/lease6-get-page.json src/share/api/lease6-resend-ddns.json diff --git a/doc/sphinx/arm/hooks-lease-cmds.rst b/doc/sphinx/arm/hooks-lease-cmds.rst index d778adf484..4728c4c79b 100644 --- a/doc/sphinx/arm/hooks-lease-cmds.rst +++ b/doc/sphinx/arm/hooks-lease-cmds.rst @@ -71,6 +71,9 @@ This library provides the following commands: - :isccmd:`lease4-get-by-hw-address` - returns all IPv4 leases with the specified hardware address. +- :isccmd:`lease6-get-by-hw-address` - returns all IPv6 leases with the specified + hardware address. + - :isccmd:`lease4-get-by-client-id` - returns all IPv4 leases with the specified ``client-id``. @@ -751,6 +754,9 @@ leases were found. .. isccmd:: lease4-get-by-hw-address .. _command-lease4-get-by-hw-address: +.. isccmd:: lease6-get-by-hw-address +.. _command-lease6-get-by-hw-address: + .. isccmd:: lease4-get-by-client-id .. _command-lease4-get-by-client-id: diff --git a/src/hooks/dhcp/lease_cmds/lease_cmds.cc b/src/hooks/dhcp/lease_cmds/lease_cmds.cc index 389cb40978..b4a4f84aeb 100644 --- a/src/hooks/dhcp/lease_cmds/lease_cmds.cc +++ b/src/hooks/dhcp/lease_cmds/lease_cmds.cc @@ -194,7 +194,7 @@ public: int leaseGetPageHandler(hooks::CalloutHandle& handle); - /// @brief lease4-get-by-hw-address command handler + /// @brief lease4-get-by-hw-address, lease6-get-by-hw-address command handler /// /// Provides the implementation for @ref isc::lease_cmds::LeaseCmds::leaseGetByHwAddressHandler /// @@ -1576,8 +1576,10 @@ LeaseCmdsImpl::leaseGetPageHandler(CalloutHandle& handle) { int LeaseCmdsImpl::leaseGetByHwAddressHandler(CalloutHandle& handle) { + bool v4 = true; try { extractCommand(handle); + v4 = (cmd_name_ == "lease4-get-by-hw-address"); // arguments must always be present if (!cmd_args_ || (cmd_args_->getType() != Element::map)) { @@ -1597,16 +1599,28 @@ LeaseCmdsImpl::leaseGetByHwAddressHandler(CalloutHandle& handle) { HWAddr hwaddr = HWAddr::fromText(hw_address->stringValue()); - Lease4Collection leases = - LeaseMgrFactory::instance().getLease4(hwaddr); ElementPtr leases_json = Element::createList(); - for (auto const& lease : leases) { - ElementPtr lease_json = lease->toElement(); - leases_json->add(lease_json); + + if (v4) { + Lease4Collection leases = + LeaseMgrFactory::instance().getLease4(hwaddr); + for (auto const& lease : leases) { + ElementPtr lease_json = lease->toElement(); + leases_json->add(lease_json); + } + } else { + Lease6Collection leases = + LeaseMgrFactory::instance().getLease6(hwaddr); + for (auto const& lease : leases) { + ElementPtr lease_json = lease->toElement(); + leases_json->add(lease_json); + } } std::ostringstream s; - s << leases_json->size() << " IPv4 lease(s) found."; + s << leases_json->size() + << " IPv" << (v4 ? "4" : "6") + << " lease(s) found."; ElementPtr args = Element::createMap(); args->set("leases", leases_json); ConstElementPtr response = diff --git a/src/hooks/dhcp/lease_cmds/lease_cmds.dox b/src/hooks/dhcp/lease_cmds/lease_cmds.dox index b1fb41c98f..37ad0e3b76 100644 --- a/src/hooks/dhcp/lease_cmds/lease_cmds.dox +++ b/src/hooks/dhcp/lease_cmds/lease_cmds.dox @@ -64,7 +64,7 @@ For details see documentation and code of the following handlers: - @ref isc::lease_cmds::LeaseCmdsImpl::leaseGetHandler (lease4-get, lease6-get) - @ref isc::lease_cmds::LeaseCmdsImpl::leaseGetAllHandler(lease4-get-all, lease6-get-all) - @ref isc::lease_cmds::LeaseCmdsImpl::leaseGetPageHandler(lease4-get-page, lease6-get-page) -- @ref isc::lease_cmds::LeaseCmdsImpl::leaseGetByHwAddressHandler(lease4-get-by-hw-address) +- @ref isc::lease_cmds::LeaseCmdsImpl::leaseGetByHwAddressHandler(lease4-get-by-hw-address, lease6-get-by-hw-address) - @ref isc::lease_cmds::LeaseCmdsImpl::leaseGetByClientIdHandler(lease4-get-by-client-id) - @ref isc::lease_cmds::LeaseCmdsImpl::leaseGetByDuidHandler(lease6-get-by-duid) - @ref isc::lease_cmds::LeaseCmdsImpl::leaseGetByHostnameHandler(lease4-get-by-hostname, lease6-get-by-hostname) diff --git a/src/hooks/dhcp/lease_cmds/lease_cmds.h b/src/hooks/dhcp/lease_cmds/lease_cmds.h index c7038ca289..4b8fdfacdc 100644 --- a/src/hooks/dhcp/lease_cmds/lease_cmds.h +++ b/src/hooks/dhcp/lease_cmds/lease_cmds.h @@ -262,12 +262,12 @@ public: int leaseGetPageHandler(hooks::CalloutHandle& handle); - /// @brief lease4-get-by-hw-address command handler + /// @brief lease4-get-by-hw-address, lease6-get-by-hw-address command handler /// - /// This command attempts to retrieve all IPv4 leases with a particular + /// This command attempts to retrieve all IPv4 or IPv6 leases with a particular /// hardware address. /// - /// Example command: + /// Example command for IPv4: /// { /// "command": "lease4-get-by-hw-address", /// "arguments": { diff --git a/src/hooks/dhcp/lease_cmds/lease_cmds_callouts.cc b/src/hooks/dhcp/lease_cmds/lease_cmds_callouts.cc index 6c37c3f7f8..ad02354d12 100644 --- a/src/hooks/dhcp/lease_cmds/lease_cmds_callouts.cc +++ b/src/hooks/dhcp/lease_cmds/lease_cmds_callouts.cc @@ -147,6 +147,17 @@ int lease4_get_by_hw_address(CalloutHandle& handle) { return (lease_cmds.leaseGetByHwAddressHandler(handle)); } +/// @brief This is a command callout for 'lease6-get-by-hw-address' command. +/// +/// @param handle Callout handle used to retrieve a command and +/// provide a response. +/// @return 0 if this callout has been invoked successfully, +/// 1 if an error occurs, 3 if no leases are returned. +int lease6_get_by_hw_address(CalloutHandle& handle) { + LeaseCmds lease_cmds; + return (lease_cmds.leaseGetByHwAddressHandler(handle)); +} + /// @brief This is a command callout for 'lease4-get-by-client-id' command. /// /// @param handle Callout handle used to retrieve a command and @@ -332,6 +343,8 @@ int load(LibraryHandle& handle) { handle.registerCommandCallout("lease6-get-page", lease6_get_page); handle.registerCommandCallout("lease4-get-by-hw-address", lease4_get_by_hw_address); + handle.registerCommandCallout("lease6-get-by-hw-address", + lease6_get_by_hw_address); handle.registerCommandCallout("lease4-get-by-client-id", lease4_get_by_client_id); handle.registerCommandCallout("lease6-get-by-duid", lease6_get_by_duid); diff --git a/src/hooks/dhcp/lease_cmds/libloadtests/lease_cmds6_unittest.cc b/src/hooks/dhcp/lease_cmds/libloadtests/lease_cmds6_unittest.cc index 3f5a8bb201..1b01ca69ac 100644 --- a/src/hooks/dhcp/lease_cmds/libloadtests/lease_cmds6_unittest.cc +++ b/src/hooks/dhcp/lease_cmds/libloadtests/lease_cmds6_unittest.cc @@ -64,7 +64,7 @@ public: /// @param pool_id expected pool-id (if value is 0 the parameter pool-id should not be present) void checkLease6(isc::data::ConstElementPtr l, std::string ip, uint8_t prefixlen, uint32_t subnet_id, std::string duid, - bool hwaddr_required, uint32_t pool_id = 0) { + std::string hwaddr = std::string(), uint32_t pool_id = 0) { ASSERT_TRUE(l); // If the element is a list we need to retrieve the lease that @@ -96,8 +96,9 @@ public: EXPECT_EQ(duid, l->get("duid")->stringValue()); // hwaddr may or may not appear - if (hwaddr_required) { - EXPECT_TRUE(l->get("hwaddr")); + if (!hwaddr.empty()) { + ASSERT_TRUE(l->get("hw-address")); + EXPECT_EQ(hwaddr, l->get("hw-address")->stringValue()); } if (pool_id) { @@ -280,6 +281,18 @@ public: /// @brief Verifies that the limit of 0 is rejected. void testLease6GetPagedLimitIsZero(); + /// @brief Check that lease6-get-by-hw-address can handle a situation when + /// the query is broken (required parameter is missing). + void testLease6GetByHwAddressParams(); + + /// @brief Check that lease6-get-by-hw-address works as expected (find no + /// lease). + void testLease6GetByHwAddressFind0(); + + /// @brief Check that lease6-get-by-hw-address works as expected (find two + /// leases). + void testLease6GetByHwAddressFind2(); + /// @brief Check that lease6-get-by-duid can handle a situation when the /// query is broken (required parameter is missing). void testLease6GetByDuidParams(); @@ -1519,7 +1532,7 @@ void Lease6CmdsTest::testLease6GetByAddr() { ASSERT_TRUE(lease); // Now check that the lease was indeed returned. - checkLease6(lease, "2001:db8:1::1", 0, 66, "42:42:42:42:42:42:42:42", false); + checkLease6(lease, "2001:db8:1::1", 0, 66, "42:42:42:42:42:42:42:42"); } void Lease6CmdsTest::testLease6GetByAddrPrefix() { // Initialize lease manager (true = v6, false = don't add leases) @@ -1554,7 +1567,7 @@ void Lease6CmdsTest::testLease6GetByAddrPrefix() { ASSERT_TRUE(lease); // Now check that the lease was indeed returned. - checkLease6(lease, "2001:db8:1234:ab::", 56, 66, "77:77:77:77:77:77:77:77", false); + checkLease6(lease, "2001:db8:1234:ab::", 56, 66, "77:77:77:77:77:77:77:77"); } void Lease6CmdsTest::testLease6GetByDuid() { @@ -1584,7 +1597,7 @@ void Lease6CmdsTest::testLease6GetByDuid() { ASSERT_TRUE(lease); // Now check that the lease was indeed returned. - checkLease6(lease, "2001:db8:1::1", 0, 66, "42:42:42:42:42:42:42:42", false); + checkLease6(lease, "2001:db8:1::1", 0, 66, "42:42:42:42:42:42:42:42"); } void Lease6CmdsTest::testLease6GetAll() { @@ -1611,10 +1624,10 @@ void Lease6CmdsTest::testLease6GetAll() { ASSERT_EQ(Element::list, leases->getType()); // Let's check if the response contains desired leases. - checkLease6(leases, "2001:db8:1::1", 0, 66, "42:42:42:42:42:42:42:42", false); - checkLease6(leases, "2001:db8:1::2", 0, 66, "56:56:56:56:56:56:56:56", false, 5); - checkLease6(leases, "2001:db8:2::1", 0, 99, "42:42:42:42:42:42:42:42", false); - checkLease6(leases, "2001:db8:2::2", 0, 99, "56:56:56:56:56:56:56:56", false); + checkLease6(leases, "2001:db8:1::1", 0, 66, "42:42:42:42:42:42:42:42"); + checkLease6(leases, "2001:db8:1::2", 0, 66, "56:56:56:56:56:56:56:56", "", 5); + checkLease6(leases, "2001:db8:2::1", 0, 99, "42:42:42:42:42:42:42:42"); + checkLease6(leases, "2001:db8:2::2", 0, 99, "56:56:56:56:56:56:56:56"); } void Lease6CmdsTest::testLease6GetAllNoLeases() { @@ -1671,8 +1684,8 @@ void Lease6CmdsTest::testLease6GetAllBySubnetId() { ASSERT_EQ(Element::list, leases->getType()); // Let's check if the response contains desired leases. - checkLease6(leases, "2001:db8:1::1", 0, 66, "42:42:42:42:42:42:42:42", false); - checkLease6(leases, "2001:db8:1::2", 0, 66, "56:56:56:56:56:56:56:56", false, 5); + checkLease6(leases, "2001:db8:1::1", 0, 66, "42:42:42:42:42:42:42:42"); + checkLease6(leases, "2001:db8:1::2", 0, 66, "56:56:56:56:56:56:56:56", "", 5); } void Lease6CmdsTest::testLease6GetAllBySubnetIdNoLeases() { @@ -1732,10 +1745,10 @@ void Lease6CmdsTest::testLease6GetAllByMultipleSubnetIds() { ASSERT_EQ(Element::list, leases->getType()); // Let's check if the response contains desired leases. - checkLease6(leases, "2001:db8:1::1", 0, 66, "42:42:42:42:42:42:42:42", false); - checkLease6(leases, "2001:db8:1::2", 0, 66, "56:56:56:56:56:56:56:56", false, 5); - checkLease6(leases, "2001:db8:2::1", 0, 99, "42:42:42:42:42:42:42:42", false); - checkLease6(leases, "2001:db8:2::2", 0, 99, "56:56:56:56:56:56:56:56", false); + checkLease6(leases, "2001:db8:1::1", 0, 66, "42:42:42:42:42:42:42:42"); + checkLease6(leases, "2001:db8:1::2", 0, 66, "56:56:56:56:56:56:56:56", "", 5); + checkLease6(leases, "2001:db8:2::1", 0, 99, "42:42:42:42:42:42:42:42"); + checkLease6(leases, "2001:db8:2::2", 0, 99, "56:56:56:56:56:56:56:56"); } void Lease6CmdsTest::testLease6GetBySubnetIdInvalidArguments() { @@ -1855,7 +1868,7 @@ void Lease6CmdsTest::testLease6GetPaged() { pool_id = 5; } checkLease6(leases, last_address, 0, from_mgr->subnet_id_, - from_mgr->duid_->toText(), false, pool_id); + from_mgr->duid_->toText(), "", pool_id); } } else { @@ -1979,6 +1992,91 @@ void Lease6CmdsTest::testLease6GetPagedLimitIsZero() { testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp); } +void Lease6CmdsTest::testLease6GetByHwAddressParams() { + // No parameters whatsoever. + string cmd = + "{\n" + " \"command\": \"lease6-get-by-hw-address\",\n" + " \"arguments\": {" + " }\n" + "}"; + string exp_rsp = "'hw-address' parameter not specified"; + testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp); + + // hw-address must be a string. + cmd = + "{\n" + " \"command\": \"lease6-get-by-hw-address\",\n" + " \"arguments\": {" + " \"hw-address\": 1234\n" + " }\n" + "}"; + exp_rsp = "'hw-address' parameter must be a string"; + testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp); + + // Simply bad value. + cmd = + "{\n" + " \"command\": \"lease6-get-by-hw-address\",\n" + " \"arguments\": {" + " \"hw-address\": \"00::01:00:bc:0d:67\"\n" + " }\n" + "}"; + exp_rsp = "two consecutive separators (':') specified in a decoded string"; + exp_rsp += " '00::01:00:bc:0d:67'"; + testCommand(cmd, CONTROL_RESULT_ERROR, exp_rsp); +} + +void Lease6CmdsTest::testLease6GetByHwAddressFind0() { + // Initialize lease manager (true = v6, false = don't add leases) + initLeaseMgr(true, false); + + // No such lease. + string cmd = + "{\n" + " \"command\": \"lease6-get-by-hw-address\",\n" + " \"arguments\": {" + " \"hw-address\": \"01:02:03:04:05:06\"\n" + " }\n" + "}"; + string exp_rsp = "0 IPv6 lease(s) found."; + testCommand(cmd, CONTROL_RESULT_EMPTY, exp_rsp); +} + +void Lease6CmdsTest::testLease6GetByHwAddressFind2() { + // Initialize lease manager (true = v6, true = add leases) + initLeaseMgr(true, true); + + // Get the lease. + string cmd = + "{\n" + " \"command\": \"lease6-get-by-hw-address\",\n" + " \"arguments\": {" + " \"hw-address\": \"08:08:08:08:08:08\"\n" + " }\n" + "}"; + string exp_rsp = "2 IPv6 lease(s) found."; + ConstElementPtr rsp = testCommand(cmd, CONTROL_RESULT_SUCCESS, exp_rsp); + + // Now check that the lease parameters were indeed returned. + ASSERT_TRUE(rsp); + ConstElementPtr map = rsp->get("arguments"); + ASSERT_TRUE(map); + ASSERT_EQ(Element::map, map->getType()); + ConstElementPtr leases = map->get("leases"); + ASSERT_TRUE(leases); + ASSERT_EQ(Element::list, leases->getType()); + ASSERT_EQ(2, leases->size()); + + // Let's check if the response makes any sense. + ConstElementPtr lease = leases->get(0); + ASSERT_TRUE(lease); + checkLease6(lease, "2001:db8:1::1", 0, 66, "42:42:42:42:42:42:42:42", "08:08:08:08:08:08"); + lease = leases->get(1); + ASSERT_TRUE(lease); + checkLease6(lease, "2001:db8:2::1", 0, 99, "42:42:42:42:42:42:42:42", "08:08:08:08:08:08"); +} + void Lease6CmdsTest::testLease6GetByDuidParams() { // No parameters whatsoever. string cmd = @@ -2058,10 +2156,10 @@ void Lease6CmdsTest::testLease6GetByDuidFind2() { // Let's check if the response makes any sense. ConstElementPtr lease = leases->get(0); ASSERT_TRUE(lease); - checkLease6(lease, "2001:db8:1::1", 0, 66, "42:42:42:42:42:42:42:42", false); + checkLease6(lease, "2001:db8:1::1", 0, 66, "42:42:42:42:42:42:42:42"); lease = leases->get(1); ASSERT_TRUE(lease); - checkLease6(lease, "2001:db8:2::1", 0, 99, "42:42:42:42:42:42:42:42", false); + checkLease6(lease, "2001:db8:2::1", 0, 99, "42:42:42:42:42:42:42:42"); } void Lease6CmdsTest::testLease6GetByHostnameParams() { @@ -2142,10 +2240,10 @@ void Lease6CmdsTest::testLease6GetByHostnameFind2() { // Let's check if the response makes any sense. ConstElementPtr lease = leases->get(0); ASSERT_TRUE(lease); - checkLease6(lease, "2001:db8:1::1", 0, 66, "42:42:42:42:42:42:42:42", false); + checkLease6(lease, "2001:db8:1::1", 0, 66, "42:42:42:42:42:42:42:42"); lease = leases->get(2); ASSERT_TRUE(lease); - checkLease6(lease, "2001:db8:2::1", 0, 99, "42:42:42:42:42:42:42:42", false); + checkLease6(lease, "2001:db8:2::1", 0, 99, "42:42:42:42:42:42:42:42"); } void Lease6CmdsTest::testLease6UpdateMissingParams() { @@ -4789,6 +4887,34 @@ TEST_F(Lease6CmdsTest, lease6GetPagedLimitIsZeroMultiThreading) { testLease6GetPagedLimitIsZero(); } +TEST_F(Lease6CmdsTest, lease6GetByHwAddressParams) { + testLease6GetByHwAddressParams(); +} + +TEST_F(Lease6CmdsTest, lease6GetByHwAddressParamsMultiThreading) { + MultiThreadingTest mt(true); + testLease6GetByHwAddressParams(); +} + +TEST_F(Lease6CmdsTest, lease6GetByHwAddressFind0) { + testLease6GetByHwAddressFind0(); +} + +TEST_F(Lease6CmdsTest, lease6GetByHwAddressFind0MultiThreading) { + MultiThreadingTest mt(true); + testLease6GetByHwAddressFind0(); +} + +TEST_F(Lease6CmdsTest, lease6GetByHwAddressFind2) { + testLease6GetByHwAddressFind2(); +} + +TEST_F(Lease6CmdsTest, lease6GetByHwAddressFind2MultiThreading) { + MultiThreadingTest mt(true); + testLease6GetByHwAddressFind2(); +} + + TEST_F(Lease6CmdsTest, lease6GetByDuidParams) { testLease6GetByDuidParams(); } diff --git a/src/hooks/dhcp/lease_cmds/libloadtests/lease_cmds_unittest.cc b/src/hooks/dhcp/lease_cmds/libloadtests/lease_cmds_unittest.cc index af751647fd..e04fd28b75 100644 --- a/src/hooks/dhcp/lease_cmds/libloadtests/lease_cmds_unittest.cc +++ b/src/hooks/dhcp/lease_cmds/libloadtests/lease_cmds_unittest.cc @@ -46,7 +46,7 @@ TEST_F(LeaseCmdsTest, commands) { "lease4-get", "lease6-get", "lease4-get-all", "lease6-get-all", "lease4-get-page", "lease6-get-page", - "lease4-get-by-hw-address", + "lease4-get-by-hw-address", "lease6-get-by-hw-address", "lease4-get-by-client-id", "lease6-get-by-duid", "lease4-get-by-hostname", "lease6-get-by-hostname", "lease4-del", "lease6-del", diff --git a/src/hooks/dhcp/lease_cmds/libloadtests/lease_cmds_unittest.h b/src/hooks/dhcp/lease_cmds/libloadtests/lease_cmds_unittest.h index 91e76eae83..a97f6e932c 100644 --- a/src/hooks/dhcp/lease_cmds/libloadtests/lease_cmds_unittest.h +++ b/src/hooks/dhcp/lease_cmds/libloadtests/lease_cmds_unittest.h @@ -360,7 +360,8 @@ public: isc::dhcp::Lease6Ptr createLease6(const std::string& ip_address, const isc::dhcp::SubnetID& subnet_id, const uint8_t duid_pattern, - bool declined = false, uint32_t pool_id = 0) { + bool declined = false, uint32_t pool_id = 0, + const uint8_t hw_address_pattern = 0) { isc::dhcp::Lease6Ptr lease(new isc::dhcp::Lease6()); lease->addr_ = isc::asiolink::IOAddress(ip_address); @@ -382,6 +383,7 @@ public: lease->fqdn_rev_ = true; lease->hostname_ = "myhost.example.com."; lease->pool_id_ = pool_id; + lease->hwaddr_.reset(new isc::dhcp::HWAddr(std::vector(6, hw_address_pattern), isc::dhcp::HTYPE_ETHER)); return (lease); } @@ -429,10 +431,10 @@ public: if (insert_lease) { if (v6) { - lmptr_->addLease(createLease6("2001:db8:1::1", 66, 0x42, declined)); - lmptr_->addLease(createLease6("2001:db8:1::2", 66, 0x56, declined, 5)); - lmptr_->addLease(createLease6("2001:db8:2::1", 99, 0x42, declined)); - lmptr_->addLease(createLease6("2001:db8:2::2", 99, 0x56, declined)); + lmptr_->addLease(createLease6("2001:db8:1::1", 66, 0x42, declined, 0, 0x08)); + lmptr_->addLease(createLease6("2001:db8:1::2", 66, 0x56, declined, 5, 0x09)); + lmptr_->addLease(createLease6("2001:db8:2::1", 99, 0x42, declined, 0, 0x08)); + lmptr_->addLease(createLease6("2001:db8:2::2", 99, 0x56, declined, 0, 0x09)); if (declined) { isc::stats::StatsMgr::instance().setValue( isc::stats::StatsMgr::generateName("subnet", 66, "declined-addresses"), diff --git a/src/hooks/dhcp/mysql/mysql_lb_messages.cc b/src/hooks/dhcp/mysql/mysql_lb_messages.cc index 6b2390f03d..9ecbd37eb0 100644 --- a/src/hooks/dhcp/mysql/mysql_lb_messages.cc +++ b/src/hooks/dhcp/mysql/mysql_lb_messages.cc @@ -33,7 +33,8 @@ extern const isc::log::MessageID MYSQL_LB_GET_EXPIRED4 = "MYSQL_LB_GET_EXPIRED4" extern const isc::log::MessageID MYSQL_LB_GET_EXPIRED6 = "MYSQL_LB_GET_EXPIRED6"; extern const isc::log::MessageID MYSQL_LB_GET_HOSTNAME4 = "MYSQL_LB_GET_HOSTNAME4"; extern const isc::log::MessageID MYSQL_LB_GET_HOSTNAME6 = "MYSQL_LB_GET_HOSTNAME6"; -extern const isc::log::MessageID MYSQL_LB_GET_HWADDR = "MYSQL_LB_GET_HWADDR"; +extern const isc::log::MessageID MYSQL_LB_GET_HWADDR4 = "MYSQL_LB_GET_HWADDR4"; +extern const isc::log::MessageID MYSQL_LB_GET_HWADDR6 = "MYSQL_LB_GET_HWADDR6"; extern const isc::log::MessageID MYSQL_LB_GET_IAID_DUID = "MYSQL_LB_GET_IAID_DUID"; extern const isc::log::MessageID MYSQL_LB_GET_IAID_SUBID_DUID = "MYSQL_LB_GET_IAID_SUBID_DUID"; extern const isc::log::MessageID MYSQL_LB_GET_PAGE4 = "MYSQL_LB_GET_PAGE4"; @@ -93,7 +94,8 @@ const char* values[] = { "MYSQL_LB_GET_EXPIRED6", "obtaining maximum %1 of expired IPv6 leases", "MYSQL_LB_GET_HOSTNAME4", "obtaining IPv4 leases for hostname %1", "MYSQL_LB_GET_HOSTNAME6", "obtaining IPv6 leases for hostname %1", - "MYSQL_LB_GET_HWADDR", "obtaining IPv4 leases for hardware address %1", + "MYSQL_LB_GET_HWADDR4", "obtaining IPv4 leases for hardware address %1", + "MYSQL_LB_GET_HWADDR6", "obtaining IPv6 leases for hardware address %1", "MYSQL_LB_GET_IAID_DUID", "obtaining IPv6 leases for IAID %1, DUID %2, lease type %3", "MYSQL_LB_GET_IAID_SUBID_DUID", "obtaining IPv6 leases for IAID %1, subnet ID %2, DUID %3, lease type %4", "MYSQL_LB_GET_PAGE4", "obtaining at most %1 IPv4 leases starting from address %2", diff --git a/src/hooks/dhcp/mysql/mysql_lb_messages.h b/src/hooks/dhcp/mysql/mysql_lb_messages.h index c775de55a4..9c49018591 100644 --- a/src/hooks/dhcp/mysql/mysql_lb_messages.h +++ b/src/hooks/dhcp/mysql/mysql_lb_messages.h @@ -34,7 +34,8 @@ extern const isc::log::MessageID MYSQL_LB_GET_EXPIRED4; extern const isc::log::MessageID MYSQL_LB_GET_EXPIRED6; extern const isc::log::MessageID MYSQL_LB_GET_HOSTNAME4; extern const isc::log::MessageID MYSQL_LB_GET_HOSTNAME6; -extern const isc::log::MessageID MYSQL_LB_GET_HWADDR; +extern const isc::log::MessageID MYSQL_LB_GET_HWADDR4; +extern const isc::log::MessageID MYSQL_LB_GET_HWADDR6; extern const isc::log::MessageID MYSQL_LB_GET_IAID_DUID; extern const isc::log::MessageID MYSQL_LB_GET_IAID_SUBID_DUID; extern const isc::log::MessageID MYSQL_LB_GET_PAGE4; diff --git a/src/hooks/dhcp/mysql/mysql_lb_messages.mes b/src/hooks/dhcp/mysql/mysql_lb_messages.mes index b5511ffa5b..f796e17861 100644 --- a/src/hooks/dhcp/mysql/mysql_lb_messages.mes +++ b/src/hooks/dhcp/mysql/mysql_lb_messages.mes @@ -143,12 +143,18 @@ A debug message issued when the server is attempting to obtain a set of IPv6 leases from the MySQL database for a client with the specified hostname. -% MYSQL_LB_GET_HWADDR obtaining IPv4 leases for hardware address %1 +% MYSQL_LB_GET_HWADDR4 obtaining IPv4 leases for hardware address %1 Logged at debug log level 50. A debug message issued when the server is attempting to obtain a set of IPv4 leases from the MySQL database for a client with the specified hardware address. +% MYSQL_LB_GET_HWADDR6 obtaining IPv6 leases for hardware address %1 +Logged at debug log level 50. +A debug message issued when the server is attempting to obtain a set +of IPv6 leases from the MySQL database for a client with the specified +hardware address. + % MYSQL_LB_GET_IAID_DUID obtaining IPv6 leases for IAID %1, DUID %2, lease type %3 Logged at debug log level 50. A debug message issued when the server is attempting to obtain a set of IPv6 diff --git a/src/hooks/dhcp/mysql/mysql_lease_mgr.cc b/src/hooks/dhcp/mysql/mysql_lease_mgr.cc index 4a51976a1d..4651e69821 100644 --- a/src/hooks/dhcp/mysql/mysql_lease_mgr.cc +++ b/src/hooks/dhcp/mysql/mysql_lease_mgr.cc @@ -301,6 +301,15 @@ tagged_statements = { { "state, user_context, pool_id " "FROM lease6 " "WHERE address = ? AND lease_type = ?"}, + {MySqlLeaseMgr::GET_LEASE6_HWADDR, + "SELECT address, duid, valid_lifetime, " + "expire, subnet_id, pref_lifetime, " + "lease_type, iaid, prefix_len, " + "fqdn_fwd, fqdn_rev, hostname, " + "hwaddr, hwtype, hwaddr_source, " + "state, user_context, pool_id " + "FROM lease6 " + "WHERE hwaddr = ?"}, {MySqlLeaseMgr::GET_LEASE6_DUID_IAID, "SELECT address, duid, valid_lifetime, " "expire, subnet_id, pref_lifetime, " @@ -2564,7 +2573,7 @@ MySqlLeaseMgr::getLease4(const IOAddress& addr) const { Lease4Collection MySqlLeaseMgr::getLease4(const HWAddr& hwaddr) const { - LOG_DEBUG(mysql_lb_logger, MYSQL_LB_DBG_TRACE_DETAIL, MYSQL_LB_GET_HWADDR) + LOG_DEBUG(mysql_lb_logger, MYSQL_LB_DBG_TRACE_DETAIL, MYSQL_LB_GET_HWADDR4) .arg(hwaddr.toText()); // Set up the WHERE clause value @@ -2874,6 +2883,47 @@ MySqlLeaseMgr::getLease6(Lease::Type lease_type, return (result); } +Lease6Collection +MySqlLeaseMgr::getLease6(const HWAddr& hwaddr) const { + LOG_DEBUG(mysql_lb_logger, MYSQL_LB_DBG_TRACE_DETAIL, MYSQL_LB_GET_HWADDR6) + .arg(hwaddr.toText()); + + // Set up the WHERE clause value + MYSQL_BIND inbind[1]; + memset(inbind, 0, sizeof(inbind)); + + inbind[0].buffer_type = MYSQL_TYPE_BLOB; + + unsigned long hwaddr_length = hwaddr.hwaddr_.size(); + + // If the data happens to be empty, we have to create a 1 byte dummy + // buffer and pass it to the binding. + uint8_t single_byte_data = 0; + + // As "buffer" is "char*" - even though the data is being read - we need + // to cast away the "const"ness as well as reinterpreting the data as + // a "char*". (We could avoid the "const_cast" by copying the data to a + // local variable, but as the data is only being read, this introduces + // an unnecessary copy). + uint8_t* data = !hwaddr.hwaddr_.empty() ? const_cast(&hwaddr.hwaddr_[0]) + : &single_byte_data; + + inbind[0].buffer = reinterpret_cast(data); + inbind[0].buffer_length = hwaddr_length; + inbind[0].length = &hwaddr_length; + + // Get the data + Lease6Collection result; + + // Get a context + MySqlLeaseContextAlloc get_context(*this); + MySqlLeaseContextPtr ctx = get_context.ctx_; + + getLeaseCollection(ctx, GET_LEASE6_HWADDR, inbind, result); + + return (result); +} + Lease6Collection MySqlLeaseMgr::getLeases6(Lease::Type lease_type, const DUID& duid, uint32_t iaid) const { diff --git a/src/hooks/dhcp/mysql/mysql_lease_mgr.h b/src/hooks/dhcp/mysql/mysql_lease_mgr.h index 3e6dae4ae1..aff7eeba67 100644 --- a/src/hooks/dhcp/mysql/mysql_lease_mgr.h +++ b/src/hooks/dhcp/mysql/mysql_lease_mgr.h @@ -338,6 +338,24 @@ public: virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress& addr) const override; + /// @brief Returns existing IPv6 leases for specified hardware address. + /// + /// Although in the usual case there will be only one lease, for mobile + /// clients or clients with multiple static/fixed/reserved leases there + /// can be more than one. Thus return type is a container, not a single + /// pointer. + /// + /// @param hwaddr hardware address of the client + /// + /// @return lease collection + /// + /// @throw isc::dhcp::DataTruncation Data was truncated on retrieval to + /// fit into the space allocated for the result. This indicates a + /// programming error. + /// @throw isc::db::DbOperationError An operation on the open database has + /// failed. + virtual Lease6Collection getLease6(const isc::dhcp::HWAddr& hwaddr) const override; + /// @brief Returns existing IPv6 leases for a given DUID+IA combination /// /// Although in the usual case there will be only one lease, for mobile @@ -756,6 +774,7 @@ public: GET_LEASE4_REMOTEID_QET, // Get page of leases by remote ID and query end time. GET_LEASE6, // Get all IPv6 leases GET_LEASE6_ADDR, // Get lease6 by address and type + GET_LEASE6_HWADDR, // Get lease6 by HW address GET_LEASE6_DUID_IAID, // Get lease6 by DUID and IAID GET_LEASE6_DUID_IAID_SUBID, // Get lease6 by DUID, IAID and subnet ID GET_LEASE6_PAGE, // Get page of leases beginning with an address diff --git a/src/hooks/dhcp/mysql/tests/mysql_lease_mgr_unittest.cc b/src/hooks/dhcp/mysql/tests/mysql_lease_mgr_unittest.cc index 7379849fe7..73431f5c06 100644 --- a/src/hooks/dhcp/mysql/tests/mysql_lease_mgr_unittest.cc +++ b/src/hooks/dhcp/mysql/tests/mysql_lease_mgr_unittest.cc @@ -911,6 +911,42 @@ TEST_F(MySqlLeaseMgrTest, testLease6HWTypeAndSourceMultiThreading) { testLease6HWTypeAndSource(); } +/// @brief Check GetLease6 methods - access by Hardware Address +TEST_F(MySqlLeaseMgrTest, getLease6HWAddr1) { + testGetLease6HWAddr1(); +} + +/// @brief Check GetLease6 methods - access by Hardware Address +TEST_F(MySqlLeaseMgrTest, getLease6HWAddr1MultiThreading) { + MultiThreadingTest mt(true); + testGetLease6HWAddr1(); +} + +/// @brief Check GetLease6 methods - access by Hardware Address +TEST_F(MySqlLeaseMgrTest, getLease6HWAddr2) { + testGetLease6HWAddr2(); +} + +/// @brief Check GetLease6 methods - access by Hardware Address +TEST_F(MySqlLeaseMgrTest, getLease6HWAddr2MultiThreading) { + MultiThreadingTest mt(true); + testGetLease6HWAddr2(); +} + +/// @brief Get lease6 by hardware address (2) +/// +/// Check that the system can cope with getting a hardware address of +/// any size. +TEST_F(MySqlLeaseMgrTest, getLease6HWAddrSize) { + testGetLease4HWAddrSize(); +} + +/// @brief Get lease6 by hardware address (2) +TEST_F(MySqlLeaseMgrTest, getLease6HWAddrSizeMultiThreading) { + MultiThreadingTest mt(true); + testGetLease6HWAddrSize(); +} + /// @brief Check that the expired DHCPv6 leases can be retrieved. /// /// This test adds a number of leases to the lease database and marks diff --git a/src/hooks/dhcp/pgsql/pgsql_lb_messages.cc b/src/hooks/dhcp/pgsql/pgsql_lb_messages.cc index 26722812a0..89eec944ef 100644 --- a/src/hooks/dhcp/pgsql/pgsql_lb_messages.cc +++ b/src/hooks/dhcp/pgsql/pgsql_lb_messages.cc @@ -32,7 +32,8 @@ extern const isc::log::MessageID PGSQL_LB_GET_EXPIRED4 = "PGSQL_LB_GET_EXPIRED4" extern const isc::log::MessageID PGSQL_LB_GET_EXPIRED6 = "PGSQL_LB_GET_EXPIRED6"; extern const isc::log::MessageID PGSQL_LB_GET_HOSTNAME4 = "PGSQL_LB_GET_HOSTNAME4"; extern const isc::log::MessageID PGSQL_LB_GET_HOSTNAME6 = "PGSQL_LB_GET_HOSTNAME6"; -extern const isc::log::MessageID PGSQL_LB_GET_HWADDR = "PGSQL_LB_GET_HWADDR"; +extern const isc::log::MessageID PGSQL_LB_GET_HWADDR4 = "PGSQL_LB_GET_HWADDR4"; +extern const isc::log::MessageID PGSQL_LB_GET_HWADDR6 = "PGSQL_LB_GET_HWADDR6"; extern const isc::log::MessageID PGSQL_LB_GET_IAID_DUID = "PGSQL_LB_GET_IAID_DUID"; extern const isc::log::MessageID PGSQL_LB_GET_IAID_SUBID_DUID = "PGSQL_LB_GET_IAID_SUBID_DUID"; extern const isc::log::MessageID PGSQL_LB_GET_PAGE4 = "PGSQL_LB_GET_PAGE4"; @@ -89,7 +90,8 @@ const char* values[] = { "PGSQL_LB_GET_EXPIRED6", "obtaining maximum %1 of expired IPv6 leases", "PGSQL_LB_GET_HOSTNAME4", "obtaining IPv4 leases for hostname %1", "PGSQL_LB_GET_HOSTNAME6", "obtaining IPv6 leases for hostname %1", - "PGSQL_LB_GET_HWADDR", "obtaining IPv4 leases for hardware address %1", + "PGSQL_LB_GET_HWADDR4", "obtaining IPv4 leases for hardware address %1", + "PGSQL_LB_GET_HWADDR6", "obtaining IPv6 leases for hardware address %1", "PGSQL_LB_GET_IAID_DUID", "obtaining IPv4 leases for IAID %1 and DUID %2, lease type %3", "PGSQL_LB_GET_IAID_SUBID_DUID", "obtaining IPv4 leases for IAID %1, subnet ID %2, DUID %3, and lease type %4", "PGSQL_LB_GET_PAGE4", "obtaining at most %1 IPv4 leases starting from address %2", diff --git a/src/hooks/dhcp/pgsql/pgsql_lb_messages.h b/src/hooks/dhcp/pgsql/pgsql_lb_messages.h index e67286859b..2b3225b304 100644 --- a/src/hooks/dhcp/pgsql/pgsql_lb_messages.h +++ b/src/hooks/dhcp/pgsql/pgsql_lb_messages.h @@ -33,7 +33,8 @@ extern const isc::log::MessageID PGSQL_LB_GET_EXPIRED4; extern const isc::log::MessageID PGSQL_LB_GET_EXPIRED6; extern const isc::log::MessageID PGSQL_LB_GET_HOSTNAME4; extern const isc::log::MessageID PGSQL_LB_GET_HOSTNAME6; -extern const isc::log::MessageID PGSQL_LB_GET_HWADDR; +extern const isc::log::MessageID PGSQL_LB_GET_HWADDR4; +extern const isc::log::MessageID PGSQL_LB_GET_HWADDR6; extern const isc::log::MessageID PGSQL_LB_GET_IAID_DUID; extern const isc::log::MessageID PGSQL_LB_GET_IAID_SUBID_DUID; extern const isc::log::MessageID PGSQL_LB_GET_PAGE4; diff --git a/src/hooks/dhcp/pgsql/pgsql_lb_messages.mes b/src/hooks/dhcp/pgsql/pgsql_lb_messages.mes index 01e763376e..ec964aec7a 100644 --- a/src/hooks/dhcp/pgsql/pgsql_lb_messages.mes +++ b/src/hooks/dhcp/pgsql/pgsql_lb_messages.mes @@ -137,12 +137,18 @@ A debug message issued when the server is attempting to obtain a set of IPv6 leases from the PostgreSQL database for a client with the specified hostname. -% PGSQL_LB_GET_HWADDR obtaining IPv4 leases for hardware address %1 +% PGSQL_LB_GET_HWADDR4 obtaining IPv4 leases for hardware address %1 Logged at debug log level 50. A debug message issued when the server is attempting to obtain a set of IPv4 leases from the PostgreSQL database for a client with the specified hardware address. +% PGSQL_LB_GET_HWADDR6 obtaining IPv6 leases for hardware address %1 +Logged at debug log level 50. +A debug message issued when the server is attempting to obtain a set +of IPv6 leases from the PostgreSQL database for a client with the specified +hardware address. + % PGSQL_LB_GET_IAID_DUID obtaining IPv4 leases for IAID %1 and DUID %2, lease type %3 Logged at debug log level 50. A debug message issued when the server is attempting to obtain a set of IPv6 diff --git a/src/hooks/dhcp/pgsql/pgsql_lease_mgr.cc b/src/hooks/dhcp/pgsql/pgsql_lease_mgr.cc index 2567e5849b..0aaddd7ebe 100644 --- a/src/hooks/dhcp/pgsql/pgsql_lease_mgr.cc +++ b/src/hooks/dhcp/pgsql/pgsql_lease_mgr.cc @@ -324,6 +324,17 @@ PgSqlTaggedStatement tagged_statements[] = { "FROM lease6 " "WHERE address = cast($1 as inet) AND lease_type = $2" }, + // GET_LEASE6_HWADDR + { 1, { OID_BYTEA }, + "get_lease6_hwaddr", + "SELECT host(address), duid, valid_lifetime, " + "extract(epoch from expire)::bigint, subnet_id, pref_lifetime, " + "lease_type, iaid, prefix_len, fqdn_fwd, fqdn_rev, hostname, " + "hwaddr, hwtype, hwaddr_source, " + "state, user_context, pool_id " + "FROM lease6 " + "WHERE hwaddr = $1" }, + // GET_LEASE6_DUID_IAID { 3, { OID_BYTEA, OID_INT8, OID_INT2 }, "get_lease6_duid_iaid", @@ -1936,7 +1947,7 @@ PgSqlLeaseMgr::getLease4(const IOAddress& addr) const { Lease4Collection PgSqlLeaseMgr::getLease4(const HWAddr& hwaddr) const { - LOG_DEBUG(pgsql_lb_logger, PGSQL_LB_DBG_TRACE_DETAIL, PGSQL_LB_GET_HWADDR) + LOG_DEBUG(pgsql_lb_logger, PGSQL_LB_DBG_TRACE_DETAIL, PGSQL_LB_GET_HWADDR4) .arg(hwaddr.toText()); // Set up the WHERE clause value @@ -2176,6 +2187,33 @@ PgSqlLeaseMgr::getLease6(Lease::Type lease_type, return (result); } +Lease6Collection +PgSqlLeaseMgr::getLease6(const HWAddr& hwaddr) const { + LOG_DEBUG(pgsql_lb_logger, PGSQL_LB_DBG_TRACE_DETAIL, PGSQL_LB_GET_HWADDR6) + .arg(hwaddr.toText()); + + // Set up the WHERE clause value + PsqlBindArray bind_array; + + // HWADDR + if (!hwaddr.hwaddr_.empty()) { + bind_array.add(hwaddr.hwaddr_); + } else { + bind_array.add(""); + } + + // Get the data + Lease6Collection result; + + // Get a context + PgSqlLeaseContextAlloc get_context(*this); + PgSqlLeaseContextPtr ctx = get_context.ctx_; + + getLeaseCollection(ctx, GET_LEASE6_HWADDR, bind_array, result); + + return (result); +} + Lease6Collection PgSqlLeaseMgr::getLeases6(Lease::Type lease_type, const DUID& duid, uint32_t iaid) const { diff --git a/src/hooks/dhcp/pgsql/pgsql_lease_mgr.h b/src/hooks/dhcp/pgsql/pgsql_lease_mgr.h index f6c13ad225..4c76bd6dcf 100644 --- a/src/hooks/dhcp/pgsql/pgsql_lease_mgr.h +++ b/src/hooks/dhcp/pgsql/pgsql_lease_mgr.h @@ -319,6 +319,21 @@ public: virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress& addr) const override; + /// @brief Returns existing IPv6 leases for specified hardware address. + /// + /// Although in the usual case there will be only one lease, for mobile + /// clients or clients with multiple static/fixed/reserved leases there + /// can be more than one. Thus return type is a container, not a single + /// pointer. + /// + /// @param hwaddr hardware address of the client + /// + /// @return lease collection + /// + /// @throw isc::db::DbOperationError An operation on the open database has + /// failed. + virtual Lease6Collection getLease6(const isc::dhcp::HWAddr& hwaddr) const override; + /// @brief Returns existing IPv6 leases for a given DUID+IA combination /// /// Although in the usual case there will be only one lease, for mobile @@ -731,6 +746,7 @@ public: GET_LEASE4_REMOTEID_QET, // Get page of leases by remote ID and query end time. GET_LEASE6, // Get all IPv6 leases GET_LEASE6_ADDR, // Get lease6 by address and type + GET_LEASE6_HWADDR, // Get lease6 by HW address GET_LEASE6_DUID_IAID, // Get lease6 by DUID and IAID GET_LEASE6_DUID_IAID_SUBID, // Get lease6 by DUID, IAID and subnet ID GET_LEASE6_PAGE, // Get page of leases beginning with an address diff --git a/src/hooks/dhcp/pgsql/tests/pgsql_lease_mgr_unittest.cc b/src/hooks/dhcp/pgsql/tests/pgsql_lease_mgr_unittest.cc index eec40a6369..b973984108 100644 --- a/src/hooks/dhcp/pgsql/tests/pgsql_lease_mgr_unittest.cc +++ b/src/hooks/dhcp/pgsql/tests/pgsql_lease_mgr_unittest.cc @@ -873,6 +873,42 @@ TEST_F(PgSqlLeaseMgrTest, testLease6HWTypeAndSourceMultiThreading) { testLease6HWTypeAndSource(); } +/// @brief Check GetLease6 methods - access by Hardware Address +TEST_F(PgSqlLeaseMgrTest, getLease6HWAddr1) { + testGetLease6HWAddr1(); +} + +/// @brief Check GetLease6 methods - access by Hardware Address +TEST_F(PgSqlLeaseMgrTest, getLease6HWAddr1MultiThreading) { + MultiThreadingTest mt(true); + testGetLease6HWAddr1(); +} + +/// @brief Check GetLease6 methods - access by Hardware Address +TEST_F(PgSqlLeaseMgrTest, getLease6HWAddr2) { + testGetLease6HWAddr2(); +} + +/// @brief Check GetLease6 methods - access by Hardware Address +TEST_F(PgSqlLeaseMgrTest, getLease6HWAddr2MultiThreading) { + MultiThreadingTest mt(true); + testGetLease6HWAddr2(); +} + +/// @brief Get lease6 by hardware address (2) +/// +/// Check that the system can cope with getting a hardware address of +/// any size. +TEST_F(PgSqlLeaseMgrTest, getLease6HWAddrSize) { + testGetLease6HWAddrSize(); +} + +/// @brief Get lease6 by hardware address (2) +TEST_F(PgSqlLeaseMgrTest, getLease6HWAddrSizeMultiThreading) { + MultiThreadingTest mt(true); + testGetLease6HWAddrSize(); +} + /// @brief Check that the expired DHCPv6 leases can be retrieved. /// /// This test adds a number of leases to the lease database and marks diff --git a/src/lib/dhcpsrv/dhcpsrv_messages.cc b/src/lib/dhcpsrv/dhcpsrv_messages.cc index 50cbed4f79..e2695f9417 100644 --- a/src/lib/dhcpsrv/dhcpsrv_messages.cc +++ b/src/lib/dhcpsrv/dhcpsrv_messages.cc @@ -111,7 +111,8 @@ extern const isc::log::MessageID DHCPSRV_MEMFILE_GET_EXPIRED4 = "DHCPSRV_MEMFILE extern const isc::log::MessageID DHCPSRV_MEMFILE_GET_EXPIRED6 = "DHCPSRV_MEMFILE_GET_EXPIRED6"; extern const isc::log::MessageID DHCPSRV_MEMFILE_GET_HOSTNAME4 = "DHCPSRV_MEMFILE_GET_HOSTNAME4"; extern const isc::log::MessageID DHCPSRV_MEMFILE_GET_HOSTNAME6 = "DHCPSRV_MEMFILE_GET_HOSTNAME6"; -extern const isc::log::MessageID DHCPSRV_MEMFILE_GET_HWADDR = "DHCPSRV_MEMFILE_GET_HWADDR"; +extern const isc::log::MessageID DHCPSRV_MEMFILE_GET_HWADDR4 = "DHCPSRV_MEMFILE_GET_HWADDR4"; +extern const isc::log::MessageID DHCPSRV_MEMFILE_GET_HWADDR6 = "DHCPSRV_MEMFILE_GET_HWADDR6"; extern const isc::log::MessageID DHCPSRV_MEMFILE_GET_IAID_DUID = "DHCPSRV_MEMFILE_GET_IAID_DUID"; extern const isc::log::MessageID DHCPSRV_MEMFILE_GET_IAID_SUBID_DUID = "DHCPSRV_MEMFILE_GET_IAID_SUBID_DUID"; extern const isc::log::MessageID DHCPSRV_MEMFILE_GET_PAGE4 = "DHCPSRV_MEMFILE_GET_PAGE4"; @@ -289,7 +290,8 @@ const char* values[] = { "DHCPSRV_MEMFILE_GET_EXPIRED6", "obtaining maximum %1 of expired IPv6 leases", "DHCPSRV_MEMFILE_GET_HOSTNAME4", "obtaining IPv4 leases for hostname %1", "DHCPSRV_MEMFILE_GET_HOSTNAME6", "obtaining IPv6 leases for hostname %1", - "DHCPSRV_MEMFILE_GET_HWADDR", "obtaining IPv4 leases for hardware address %1", + "DHCPSRV_MEMFILE_GET_HWADDR4", "obtaining IPv4 leases for hardware address %1", + "DHCPSRV_MEMFILE_GET_HWADDR6", "obtaining IPv6 leases for hardware address %1", "DHCPSRV_MEMFILE_GET_IAID_DUID", "obtaining IPv6 leases for IAID %1 and DUID %2 and lease type %3", "DHCPSRV_MEMFILE_GET_IAID_SUBID_DUID", "obtaining IPv6 leases for IAID %1, Subnet ID %2, DUID %3 and lease type %4", "DHCPSRV_MEMFILE_GET_PAGE4", "obtaining at most %1 IPv4 leases starting from address %2", diff --git a/src/lib/dhcpsrv/dhcpsrv_messages.h b/src/lib/dhcpsrv/dhcpsrv_messages.h index c0a1af1825..6598a9c364 100644 --- a/src/lib/dhcpsrv/dhcpsrv_messages.h +++ b/src/lib/dhcpsrv/dhcpsrv_messages.h @@ -112,7 +112,8 @@ extern const isc::log::MessageID DHCPSRV_MEMFILE_GET_EXPIRED4; extern const isc::log::MessageID DHCPSRV_MEMFILE_GET_EXPIRED6; extern const isc::log::MessageID DHCPSRV_MEMFILE_GET_HOSTNAME4; extern const isc::log::MessageID DHCPSRV_MEMFILE_GET_HOSTNAME6; -extern const isc::log::MessageID DHCPSRV_MEMFILE_GET_HWADDR; +extern const isc::log::MessageID DHCPSRV_MEMFILE_GET_HWADDR4; +extern const isc::log::MessageID DHCPSRV_MEMFILE_GET_HWADDR6; extern const isc::log::MessageID DHCPSRV_MEMFILE_GET_IAID_DUID; extern const isc::log::MessageID DHCPSRV_MEMFILE_GET_IAID_SUBID_DUID; extern const isc::log::MessageID DHCPSRV_MEMFILE_GET_PAGE4; diff --git a/src/lib/dhcpsrv/dhcpsrv_messages.mes b/src/lib/dhcpsrv/dhcpsrv_messages.mes index 6036d72c8d..e258042bdb 100644 --- a/src/lib/dhcpsrv/dhcpsrv_messages.mes +++ b/src/lib/dhcpsrv/dhcpsrv_messages.mes @@ -633,12 +633,18 @@ A debug message issued when the server is attempting to obtain a set of IPv6 leases from the memory file database for a client with the specified hostname. -% DHCPSRV_MEMFILE_GET_HWADDR obtaining IPv4 leases for hardware address %1 +% DHCPSRV_MEMFILE_GET_HWADDR4 obtaining IPv4 leases for hardware address %1 Logged at debug log level 50. A debug message issued when the server is attempting to obtain a set of IPv4 leases from the memory file database for a client with the specified hardware address. +% DHCPSRV_MEMFILE_GET_HWADDR6 obtaining IPv6 leases for hardware address %1 +Logged at debug log level 50. +A debug message issued when the server is attempting to obtain a set of +IPv6 leases from the memory file database for a client with the specified +hardware address. + % DHCPSRV_MEMFILE_GET_IAID_DUID obtaining IPv6 leases for IAID %1 and DUID %2 and lease type %3 Logged at debug log level 50. A debug message issued when the server is attempting to obtain a set of IPv6 diff --git a/src/lib/dhcpsrv/lease.cc b/src/lib/dhcpsrv/lease.cc index 798173aee9..2eede95057 100644 --- a/src/lib/dhcpsrv/lease.cc +++ b/src/lib/dhcpsrv/lease.cc @@ -553,8 +553,8 @@ Lease6::toText() const { << "Pref life: " << lifetimeToText(preferred_lft_) << "\n" << "Valid life: " << lifetimeToText(valid_lft_) << "\n" << "Cltt: " << cltt_ << "\n" - << "DUID: " << (duid_?duid_->toText():"(none)") << "\n" - << "Hardware addr: " << (hwaddr_?hwaddr_->toText(false):"(none)") << "\n" + << "DUID: " << (duid_ ? duid_->toText() : "(none)") << "\n" + << "Hardware addr: " << (hwaddr_ ? hwaddr_->toText(false) : "(none)") << "\n" << "Subnet ID: " << subnet_id_ << "\n" << "Pool ID: " << pool_id_ << "\n" << "State: " << statesToText(state_) << "\n"; diff --git a/src/lib/dhcpsrv/lease_mgr.h b/src/lib/dhcpsrv/lease_mgr.h index c16d995a02..dd6b4a975e 100644 --- a/src/lib/dhcpsrv/lease_mgr.h +++ b/src/lib/dhcpsrv/lease_mgr.h @@ -409,6 +409,18 @@ public: virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress& addr) const = 0; + /// @brief Returns existing IPv6 leases for specified hardware address. + /// + /// Although in the usual case there will be only one lease, for mobile + /// clients or clients with multiple static/fixed/reserved leases there + /// can be more than one. Thus return type is a container, not a single + /// pointer. + /// + /// @param hwaddr hardware address of the client + /// + /// @return lease collection + virtual Lease6Collection getLease6(const isc::dhcp::HWAddr& hwaddr) const = 0; + /// @brief Returns existing IPv6 leases for a given DUID+IA combination /// /// Although in the usual case there will be only one lease, for mobile diff --git a/src/lib/dhcpsrv/memfile_lease_mgr.cc b/src/lib/dhcpsrv/memfile_lease_mgr.cc index 3d6075fb9f..84eef4842b 100644 --- a/src/lib/dhcpsrv/memfile_lease_mgr.cc +++ b/src/lib/dhcpsrv/memfile_lease_mgr.cc @@ -1209,7 +1209,7 @@ Memfile_LeaseMgr::getLease4Internal(const HWAddr& hwaddr, Lease4Collection Memfile_LeaseMgr::getLease4(const HWAddr& hwaddr) const { LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, - DHCPSRV_MEMFILE_GET_HWADDR).arg(hwaddr.toText()); + DHCPSRV_MEMFILE_GET_HWADDR4).arg(hwaddr.toText()); Lease4Collection collection; if (MultiThreadingMgr::instance().getMode()) { @@ -1456,6 +1456,38 @@ Memfile_LeaseMgr::getLease6Internal(Lease::Type type, } } +void +Memfile_LeaseMgr::getLease6Internal(const HWAddr& hwaddr, + Lease6Collection& collection) const { + // Using composite index by 'hw address' and 'subnet id'. It is + // ok to use it for searching by the 'hw address' only. + const Lease6StorageHWAddressSubnetIdIndex& idx = + storage6_.get(); + std::pair l + = idx.equal_range(boost::make_tuple(hwaddr.hwaddr_)); + + BOOST_FOREACH(auto const& lease, l) { + collection.push_back(Lease6Ptr(new Lease6(*lease))); + } +} + +Lease6Collection +Memfile_LeaseMgr::getLease6(const HWAddr& hwaddr) const { + LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, + DHCPSRV_MEMFILE_GET_HWADDR6).arg(hwaddr.toText()); + + Lease6Collection collection; + if (MultiThreadingMgr::instance().getMode()) { + std::lock_guard lock(*mutex_); + getLease6Internal(hwaddr, collection); + } else { + getLease6Internal(hwaddr, collection); + } + + return (collection); +} + Lease6Ptr Memfile_LeaseMgr::getAnyLease6Internal(const isc::asiolink::IOAddress& addr) const { Lease6Storage::iterator l = storage6_.find(addr); diff --git a/src/lib/dhcpsrv/memfile_lease_mgr.h b/src/lib/dhcpsrv/memfile_lease_mgr.h index 026917b298..42c809380f 100644 --- a/src/lib/dhcpsrv/memfile_lease_mgr.h +++ b/src/lib/dhcpsrv/memfile_lease_mgr.h @@ -295,6 +295,18 @@ public: virtual Lease6Ptr getLease6(Lease::Type type, const isc::asiolink::IOAddress& addr) const override; + /// @brief Returns existing IPv6 leases for specified hardware address. + /// + /// Although in the usual case there will be only one lease, for mobile + /// clients or clients with multiple static/fixed/reserved leases there + /// can be more than one. Thus return type is a container, not a single + /// pointer. + /// + /// @param hwaddr hardware address of the client + /// + /// @return lease collection + virtual Lease6Collection getLease6(const isc::dhcp::HWAddr& hwaddr) const override; + /// @brief Returns existing IPv6 lease for a given DUID + IA + lease type /// combination /// @@ -666,6 +678,13 @@ private: Lease6Ptr getLease6Internal(Lease::Type type, const isc::asiolink::IOAddress& addr) const; + /// @brief Gets existing IPv6 leases for specified hardware address. + /// + /// @param hwaddr hardware address of the client + /// @param collection lease collection + void getLease6Internal(const isc::dhcp::HWAddr& hwaddr, + Lease6Collection& collection) const; + /// @brief Returns existing IPv6 lease of any type for a given IPv6 address. /// /// @param addr An address of the searched lease. diff --git a/src/lib/dhcpsrv/memfile_lease_storage.h b/src/lib/dhcpsrv/memfile_lease_storage.h index 24e6a2e682..006bafff2e 100644 --- a/src/lib/dhcpsrv/memfile_lease_storage.h +++ b/src/lib/dhcpsrv/memfile_lease_storage.h @@ -174,6 +174,27 @@ typedef boost::multi_index_container< // than derived class: Lease6. boost::multi_index::member > + >, + + // Specification of the eight index starts here. + boost::multi_index::ordered_non_unique< + boost::multi_index::tag, + // This is a composite index that combines two attributes of the + // Lease6 object: hardware address and subnet id. + boost::multi_index::composite_key< + Lease6, + // The hardware address is held in the hwaddr_ member of the + // Lease4 object, which is a HWAddr object. Boost does not + // provide a key extractor for getting a member of a member, + // so we need a simple method for that. + boost::multi_index::const_mem_fun&, + &Lease::getHWAddrVector>, + // The subnet id is held in the subnet_id_ member of Lease6 + // class. Note that the subnet_id_ is defined in the base + // class (Lease) so we have to point to this class rather + // than derived class: Lease6. + boost::multi_index::member + > > > > Lease6Storage; // Specify the type name of this container. @@ -343,6 +364,10 @@ typedef Lease6Storage::index::type Lease6StorageDuidIaidTy /// @brief DHCPv6 lease storage index by expiration time. typedef Lease6Storage::index::type Lease6StorageExpirationIndex; +/// @brief DHCPv6 lease storage index by HW address and subnet-id. +typedef Lease6Storage::index::type +Lease6StorageHWAddressSubnetIdIndex; + /// @brief DHCPv6 lease storage index by subnet-id. typedef Lease6Storage::index::type Lease6StorageSubnetIdIndex; diff --git a/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc b/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc index ec0286a0d0..12b1b17a4f 100644 --- a/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc @@ -1549,6 +1549,35 @@ TEST_F(MemfileLeaseMgrTest, testLease6MacMultiThread) { testLease6MAC(); } +/// @brief Checks lease6 retrieval through HWAddr +TEST_F(MemfileLeaseMgrTest, getLease6HWAddr1) { + startBackend(V6); + testGetLease6HWAddr1(); +} + +/// @brief Checks lease6 retrieval through HWAddr +TEST_F(MemfileLeaseMgrTest, getLease6HWAddr1MultiThread) { + startBackend(V6); + MultiThreadingMgr::instance().setMode(true); + testGetLease6HWAddr1(); +} + +/// @brief Check GetLease6 methods - access by Hardware Address +/// +/// Adds leases to the database and checks that they can be accessed via +/// a combination of DUID and IAID. +TEST_F(MemfileLeaseMgrTest, getLease6HWAddr2) { + startBackend(V6); + testGetLease6HWAddr2(); +} + +/// @brief Check GetLease6 methods - access by Hardware Address +TEST_F(MemfileLeaseMgrTest, getLease6HWAddr2MultiThread) { + startBackend(V6); + MultiThreadingMgr::instance().setMode(true); + testGetLease6HWAddr2(); +} + /// @brief Check that memfile reports version correctly. TEST_F(MemfileLeaseMgrTest, versionCheck) { // Check that V4 backend reports versions correctly. diff --git a/src/lib/dhcpsrv/testutils/concrete_lease_mgr.cc b/src/lib/dhcpsrv/testutils/concrete_lease_mgr.cc index 616ca15bf6..40ea946e4f 100644 --- a/src/lib/dhcpsrv/testutils/concrete_lease_mgr.cc +++ b/src/lib/dhcpsrv/testutils/concrete_lease_mgr.cc @@ -87,6 +87,11 @@ ConcreteLeaseMgr::getLease6(Lease::Type /* not used yet */, return (Lease6Ptr()); } +Lease6Collection +ConcreteLeaseMgr::getLease6(const HWAddr&) const { + return (Lease6Collection()); +} + Lease6Collection ConcreteLeaseMgr::getLeases6(Lease::Type /* not used yet */, const DUID&, uint32_t) const { diff --git a/src/lib/dhcpsrv/testutils/concrete_lease_mgr.h b/src/lib/dhcpsrv/testutils/concrete_lease_mgr.h index 0fc468e940..19a6ebab53 100644 --- a/src/lib/dhcpsrv/testutils/concrete_lease_mgr.h +++ b/src/lib/dhcpsrv/testutils/concrete_lease_mgr.h @@ -148,6 +148,18 @@ public: virtual Lease6Ptr getLease6(Lease::Type /* not used yet */, const isc::asiolink::IOAddress&) const override; + /// @brief Returns existing IPv6 leases for specified hardware address. + /// + /// Although in the usual case there will be only one lease, for mobile + /// clients or clients with multiple static/fixed/reserved leases there + /// can be more than one. Thus return type is a container, not a single + /// pointer. + /// + /// @param hwaddr hardware address of the client + /// + /// @return lease collection + virtual Lease6Collection getLease6(const HWAddr&) const override; + /// @brief Returns existing IPv6 lease for a given DUID+IA combination /// /// @param duid ignored diff --git a/src/lib/dhcpsrv/testutils/generic_lease_mgr_unittest.cc b/src/lib/dhcpsrv/testutils/generic_lease_mgr_unittest.cc index 20c9865985..008ccaf89f 100644 --- a/src/lib/dhcpsrv/testutils/generic_lease_mgr_unittest.cc +++ b/src/lib/dhcpsrv/testutils/generic_lease_mgr_unittest.cc @@ -229,6 +229,7 @@ GenericLeaseMgrTest::initializeLease6(std::string address) { // Set other parameters. For historical reasons, address 0 is not used. if (address == straddress6_[0]) { + lease->hwaddr_.reset(new HWAddr(vector(6, 0x08), HTYPE_ETHER)); lease->type_ = leasetype6_[0]; lease->prefixlen_ = 128; lease->iaid_ = 142; @@ -243,6 +244,7 @@ GenericLeaseMgrTest::initializeLease6(std::string address) { lease->hostname_ = "myhost.example.com."; } else if (address == straddress6_[1]) { + lease->hwaddr_.reset(new HWAddr(vector(6, 0x19), HTYPE_ETHER)); lease->type_ = leasetype6_[1]; lease->prefixlen_ = 128; lease->iaid_ = 42; @@ -258,6 +260,7 @@ GenericLeaseMgrTest::initializeLease6(std::string address) { lease->pool_id_ = 7; } else if (address == straddress6_[2]) { + lease->hwaddr_.reset(new HWAddr(vector(6, 0x2a), HTYPE_ETHER)); lease->type_ = leasetype6_[2]; lease->prefixlen_ = 48; lease->iaid_ = 89; @@ -272,6 +275,8 @@ GenericLeaseMgrTest::initializeLease6(std::string address) { lease->hostname_ = "myhost.example.com."; } else if (address == straddress6_[3]) { + // Hardware address same as lease 1. + lease->hwaddr_.reset(new HWAddr(vector(6, 0x19), HTYPE_ETHER)); lease->type_ = leasetype6_[3]; lease->prefixlen_ = 128; lease->iaid_ = 0xfffffffe; @@ -295,6 +300,7 @@ GenericLeaseMgrTest::initializeLease6(std::string address) { lease->hostname_ = "myhost.example.com."; } else if (address == straddress6_[4]) { + lease->hwaddr_.reset(new HWAddr(vector(6, 0x4c), HTYPE_ETHER)); // Same DUID and IAID as straddress6_1 lease->type_ = leasetype6_[4]; lease->prefixlen_ = 128; @@ -310,6 +316,8 @@ GenericLeaseMgrTest::initializeLease6(std::string address) { lease->hostname_ = "otherhost.example.com."; } else if (address == straddress6_[5]) { + // Same as lease 1 + lease->hwaddr_.reset(new HWAddr(vector(6, 0x19), HTYPE_ETHER)); // Same DUID and IAID as straddress6_1 lease->type_ = leasetype6_[5]; lease->prefixlen_ = 56; @@ -327,6 +335,7 @@ GenericLeaseMgrTest::initializeLease6(std::string address) { lease->setContext(Element::fromJSON("{ \"foo\": true }")); } else if (address == straddress6_[6]) { + lease->hwaddr_.reset(new HWAddr(vector(6, 0x6e), HTYPE_ETHER)); // Same DUID as straddress6_1 lease->type_ = leasetype6_[6]; lease->prefixlen_ = 128; @@ -343,6 +352,7 @@ GenericLeaseMgrTest::initializeLease6(std::string address) { lease->hostname_ = "hostname.example.com."; } else if (address == straddress6_[7]) { + lease->hwaddr_.reset(new HWAddr(vector(), HTYPE_ETHER)); // Empty // Same IAID as straddress6_1 lease->type_ = leasetype6_[7]; lease->prefixlen_ = 128; @@ -606,8 +616,9 @@ GenericLeaseMgrTest::testGetLease4HWAddr2() { detailCompareLease(leases[7], *returned.begin()); // Try to get something with invalid hardware address - vector invalid(6, 0); - returned = lmptr_->getLease4(invalid); + HWAddr hwaddr(vector(6, 0x80), HTYPE_ETHER); + hwaddr.hwaddr_ = vector(6, 0); + returned = lmptr_->getLease4(hwaddr); EXPECT_EQ(0, returned.size()); } @@ -1008,6 +1019,77 @@ GenericLeaseMgrTest::testLease6HWTypeAndSource() { EXPECT_FALSE(stored3->hwaddr_); } +void +GenericLeaseMgrTest::testGetLease6HWAddr1() { + // Let's initialize two different leases 6 and just add the first ... + Lease6Ptr leaseA = initializeLease6(straddress6_[5]); + HWAddr hwaddrA(*leaseA->hwaddr_); + HWAddr hwaddrB(vector(6, 0x80), HTYPE_ETHER); + + EXPECT_TRUE(lmptr_->addLease(leaseA)); + + // we should not have a lease, with this HWAddr + Lease6Collection returned = lmptr_->getLease6(hwaddrB); + ASSERT_EQ(0, returned.size()); + + // But with this one + returned = lmptr_->getLease6(hwaddrA); + ASSERT_EQ(1, returned.size()); +} + +void +GenericLeaseMgrTest::testGetLease6HWAddr2() { + // Get the leases to be used for the test and add to the database + vector leases = createLeases6(); + for (size_t i = 0; i < leases.size(); ++i) { + EXPECT_TRUE(lmptr_->addLease(leases[i])); + } + + // Get the leases matching the hardware address of lease 1 + HWAddr tmp(*leases[1]->hwaddr_); + Lease6Collection returned = lmptr_->getLease6(tmp); + + // Should be three leases, matching leases[1], [3] and [5]. + ASSERT_EQ(3, returned.size()); + + // Check the lease[5] (and only this one) has an user context. + size_t contexts = 0; + for (auto const& i : returned) { + if (i->getContext()) { + ++contexts; + EXPECT_EQ("{ \"foo\": true }", i->getContext()->str()); + } + } + EXPECT_EQ(1, contexts); + + // Easiest way to check is to look at the addresses. + vector addresses; + for (auto const& i : returned) { + addresses.push_back(i->addr_.toText()); + } + sort(addresses.begin(), addresses.end()); + EXPECT_EQ(straddress6_[1], addresses[0]); + EXPECT_EQ(straddress6_[3], addresses[1]); + EXPECT_EQ(straddress6_[5], addresses[2]); + + // Repeat test with just one expected match + returned = lmptr_->getLease6(*leases[2]->hwaddr_); + ASSERT_EQ(1, returned.size()); + detailCompareLease(leases[2], *returned.begin()); + + // Check that an empty vector is valid + EXPECT_TRUE(leases[7]->hwaddr_->hwaddr_.empty()); + returned = lmptr_->getLease6(*leases[7]->hwaddr_); + ASSERT_EQ(1, returned.size()); + detailCompareLease(leases[7], *returned.begin()); + + // Try to get something with invalid hardware address + HWAddr hwaddr(vector(6, 0x80), HTYPE_ETHER); + hwaddr.hwaddr_ = vector(6, 0); + returned = lmptr_->getLease6(hwaddr); + EXPECT_EQ(0, returned.size()); +} + void GenericLeaseMgrTest::testLease4InvalidHostname() { // Get the leases to be used for the test. @@ -1077,6 +1159,29 @@ GenericLeaseMgrTest::testGetLease4HWAddrSize() { EXPECT_THROW(lmptr_->addLease(leases[1]), isc::db::DbOperationError); } +void +GenericLeaseMgrTest::testGetLease6HWAddrSize() { + // Create leases, although we need only one. + vector leases = createLeases6(); + + // Now add leases with increasing hardware address size. + for (uint8_t i = 0; i <= HWAddr::MAX_HWADDR_LEN; ++i) { + leases[1]->hwaddr_->hwaddr_.resize(i, i); + EXPECT_TRUE(lmptr_->addLease(leases[1])); + Lease6Collection returned = + lmptr_->getLease6(*leases[1]->hwaddr_); + + ASSERT_EQ(1, returned.size()); + detailCompareLease(leases[1], *returned.begin()); + ASSERT_TRUE(lmptr_->deleteLease(leases[1])); + } + + // Database should not let us add one that is too big + // (The 42 is a random value put in each byte of the address.) + leases[1]->hwaddr_->hwaddr_.resize(HWAddr::MAX_HWADDR_LEN + 100, 42); + EXPECT_THROW(lmptr_->addLease(leases[1]), isc::db::DbOperationError); +} + void GenericLeaseMgrTest::testGetLease4HWAddrSubnetId() { // Get the leases to be used for the test and add to the database diff --git a/src/lib/dhcpsrv/testutils/generic_lease_mgr_unittest.h b/src/lib/dhcpsrv/testutils/generic_lease_mgr_unittest.h index d1492155e7..fea4b309a8 100644 --- a/src/lib/dhcpsrv/testutils/generic_lease_mgr_unittest.h +++ b/src/lib/dhcpsrv/testutils/generic_lease_mgr_unittest.h @@ -314,6 +314,21 @@ public: /// @brief Checks that Lease6 stores hardware type and hardware source. void testLease6HWTypeAndSource(); + /// @brief Test lease retrieval using HW address. + void testGetLease6HWAddr1(); + + /// @brief Check GetLease4 methods - access by Hardware Address + /// + /// Adds leases to the database and checks that they can be accessed using + /// HWAddr information. + void testGetLease6HWAddr2(); + + /// @brief Get lease4 by hardware address (2) + /// + /// Check that the system can cope with getting a hardware address of + /// any size. + void testGetLease6HWAddrSize(); + /// @brief Test that IPv6 lease can be added, retrieved and deleted. void testAddGetDelete6(); diff --git a/src/share/api/lease6-get-by-hw-address.json b/src/share/api/lease6-get-by-hw-address.json new file mode 100644 index 0000000000..b044adbdc3 --- /dev/null +++ b/src/share/api/lease6-get-by-hw-address.json @@ -0,0 +1,51 @@ +{ + "access": "read", + "avail": "3.1.1", + "brief": [ + "This command retrieves all IPv6 leases with the specified hardware address." + ], + "cmd-syntax": [ + "{", + " \"command\": \"lease6-get-by-hw-address\",", + " \"arguments\": {", + " \"hw-address\": \"00:0c:01:02:03:04\"", + " }", + "}" + ], + "description": "See ", + "hook": "lease_cmds", + "name": "lease6-get-by-hw-address", + "resp-comment": [ + "Result 0 is returned when at least one lease is found, 1 when parameters are malformed or missing,", + "3 is returned if no leases are found." + ], + "resp-syntax": [ + " {", + " \"arguments\": {", + " \"leases\": [", + " {", + " \"cltt\": 1600439560,", + " \"duid\": \"00:01:00:01:26:f7:81:88:00:0c:01:02:03:04\",", + " \"fqdn-fwd\": false,", + " \"fqdn-rev\": false,", + " \"hostname\": \"foobar.example.org\",", + " \"hw-address\": \"00:0c:01:02:03:04\",", + " \"iaid\": 1,", + " \"ip-address\": \"2001:db8:1::\",", + " \"preferred-lft\": 3000,", + " \"state\": 0,", + " \"subnet-id\": 1,", + " \"type\": \"IA_NA\",", + " \"valid-lft\": 4000", + " }", + " ]", + " },", + " \"result\": 0,", + " \"text\": \"1 IPv6 lease(s) found.\"", + " }" + ], + + "support": [ + "kea-dhcp6" + ] +} -- 2.47.2