]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3826] Implemented lease6-get-by-hw-address command.
authorRazvan Becheriu <razvan@isc.org>
Thu, 24 Jul 2025 15:32:50 +0000 (18:32 +0300)
committerRazvan Becheriu <razvan@isc.org>
Thu, 31 Jul 2025 14:22:37 +0000 (14:22 +0000)
35 files changed:
doc/sphinx/api-files.txt
doc/sphinx/arm/hooks-lease-cmds.rst
src/hooks/dhcp/lease_cmds/lease_cmds.cc
src/hooks/dhcp/lease_cmds/lease_cmds.dox
src/hooks/dhcp/lease_cmds/lease_cmds.h
src/hooks/dhcp/lease_cmds/lease_cmds_callouts.cc
src/hooks/dhcp/lease_cmds/libloadtests/lease_cmds6_unittest.cc
src/hooks/dhcp/lease_cmds/libloadtests/lease_cmds_unittest.cc
src/hooks/dhcp/lease_cmds/libloadtests/lease_cmds_unittest.h
src/hooks/dhcp/mysql/mysql_lb_messages.cc
src/hooks/dhcp/mysql/mysql_lb_messages.h
src/hooks/dhcp/mysql/mysql_lb_messages.mes
src/hooks/dhcp/mysql/mysql_lease_mgr.cc
src/hooks/dhcp/mysql/mysql_lease_mgr.h
src/hooks/dhcp/mysql/tests/mysql_lease_mgr_unittest.cc
src/hooks/dhcp/pgsql/pgsql_lb_messages.cc
src/hooks/dhcp/pgsql/pgsql_lb_messages.h
src/hooks/dhcp/pgsql/pgsql_lb_messages.mes
src/hooks/dhcp/pgsql/pgsql_lease_mgr.cc
src/hooks/dhcp/pgsql/pgsql_lease_mgr.h
src/hooks/dhcp/pgsql/tests/pgsql_lease_mgr_unittest.cc
src/lib/dhcpsrv/dhcpsrv_messages.cc
src/lib/dhcpsrv/dhcpsrv_messages.h
src/lib/dhcpsrv/dhcpsrv_messages.mes
src/lib/dhcpsrv/lease.cc
src/lib/dhcpsrv/lease_mgr.h
src/lib/dhcpsrv/memfile_lease_mgr.cc
src/lib/dhcpsrv/memfile_lease_mgr.h
src/lib/dhcpsrv/memfile_lease_storage.h
src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc
src/lib/dhcpsrv/testutils/concrete_lease_mgr.cc
src/lib/dhcpsrv/testutils/concrete_lease_mgr.h
src/lib/dhcpsrv/testutils/generic_lease_mgr_unittest.cc
src/lib/dhcpsrv/testutils/generic_lease_mgr_unittest.h
src/share/api/lease6-get-by-hw-address.json [new file with mode: 0644]

index db6964b81432c420d427d1d4c675459ff0d71d88..b8a89815dacdbd3c4c2485ed42559fa5e015cc06 100644 (file)
@@ -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
index d778adf484959dbc0fef4beec2ba2e3e5e79223f..4728c4c79b307ab95445794acfe843d45bda07c1 100644 (file)
@@ -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:
 
index 389cb4097840d362357879bdfd09ada72a2b1f65..b4a4f84aeb1b889e5c708e588f3d2e91458a73a3 100644 (file)
@@ -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 =
index b1fb41c98f91fee390d094b30d4c842ab182b616..37ad0e3b76ea580b5e842e5799df42b612e5f1de 100644 (file)
@@ -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)
index c7038ca28915b0d480c9fda90cd6a919c613b586..4b8fdfacdcb74710891012977b90b192728ba73e 100644 (file)
@@ -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": {
index 6c37c3f7f820ff83783b620dbd21c7da97f4e6e7..ad02354d121e1a52a88963835264c99c901497bc 100644 (file)
@@ -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);
index 3f5a8bb2016ce878d2daedac7b0ddbb114d48c11..1b01ca69ac79e6d4d189963474528c03203621f0 100644 (file)
@@ -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();
 }
index af751647fdc9b886fc943c2c3533fc3e1d607850..e04fd28b7504233cc42b1148f455202e5273a1cc 100644 (file)
@@ -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",
index 91e76eae83d4a483b9999580f073d656023a51ff..a97f6e932c54e20c8f27761fdfefb95d2a81f01b 100644 (file)
@@ -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<uint8_t>(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"),
index 6b2390f03d0ac38d53d15d85a8a52d0f6a84f5fc..9ecbd37eb0ee7b692b0b7fdb5602dc57aa2c1b5d 100644 (file)
@@ -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",
index c775de55a438f72c3eacb54a530213f1bf3914cd..9c4901859142998ad1916389a735cbfea00f7db4 100644 (file)
@@ -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;
index b5511ffa5b3282dc49f64f78f5c6407fb9eb90c7..f796e17861d341f3fb63ec90bcb143a0131dd1f8 100644 (file)
@@ -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
index 4a51976a1d4e83be93303e8270eb7c1d822e12cc..4651e698213c8146ebbc32b85ff30c8bdc19c9d6 100644 (file)
@@ -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<uint8_t*>(&hwaddr.hwaddr_[0])
+        : &single_byte_data;
+
+    inbind[0].buffer = reinterpret_cast<char*>(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 {
index 3e6dae4ae1959efa7e37d30089eb5f635fdfccce..aff7eeba674a8c4dae97fe8847845d19205ab143 100644 (file)
@@ -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
index 7379849fe73f6f6cfb7ed4adc6c4a7e6d6cd3b4a..73431f5c067a3d3904aaf51bc87ebfb7355a03fe 100644 (file)
@@ -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
index 26722812a099b5c63f1cf01c239a10043d3023ec..89eec944effba16d4d1285000d00ceb88763469e 100644 (file)
@@ -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",
index e67286859be3ad9868988f4065266dde00994f0e..2b3225b304075ed84a49a32345358c6b8fa16a0f 100644 (file)
@@ -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;
index 01e763376ea86b73867c31c75ce88b11e78b46c9..ec964aec7a83b9792fc89e2df6d7edb005a3b28b 100644 (file)
@@ -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
index 2567e5849b526e98c007dfd8038bc881b1936235..0aaddd7ebeef01fc4f50f24b6b3c8d11411601fa 100644 (file)
@@ -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 {
index f6c13ad225514aad611b73f94ed5e97dacf6a19f..4c76bd6dcf91248b7c027dbf46fe30ad5d1dc5b0 100644 (file)
@@ -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
index eec40a6369208290bc5f8da6e7454b912f096a6f..b9739841080d33311d76d06855865a024047da0b 100644 (file)
@@ -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
index 50cbed4f79e27f9957ab797bc928bff2525289b4..e2695f94171d3c9b7a7fd659900fa2253599ab01 100644 (file)
@@ -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",
index c0a1af18251298ac281c4ac4cefd86e7b4a70435..6598a9c36429d27e4b00cb1d01068388a2086716 100644 (file)
@@ -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;
index 6036d72c8dd1831f8734a6ae8bd66794f14ea672..e258042bdb945e3f1c34b1281e2cb20366abc941 100644 (file)
@@ -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
index 798173aee911388d03a5da683662f237f86c1f62..2eede950578a7c56fad61c2acc6b9df93775cefb 100644 (file)
@@ -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";
index c16d995a02a133dd32f73efeaf0561acabd2f3ba..dd6b4a975e5dc16a44989c828bf108a6cbf50ebe 100644 (file)
@@ -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
index 3d6075fb9fd3e30a7d1ab81cf3b1f1cadb1f4a26..84eef4842b4fba41af523f6d7cd36d15e3350bab 100644 (file)
@@ -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<HWAddressSubnetIdIndexTag>();
+    std::pair<Lease6StorageHWAddressSubnetIdIndex::const_iterator,
+              Lease6StorageHWAddressSubnetIdIndex::const_iterator> 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<std::mutex> 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);
index 026917b29882bd0bc375afe2313d877ee91cd959..42c809380f0b30ac1c54110e1b2563919a4ed385 100644 (file)
@@ -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.
index 24e6a2e682077f711ce77cb0f4dfc019c0c83981..006bafff2ec7e5cdcf960ba488b047f9ce40195c 100644 (file)
@@ -174,6 +174,27 @@ typedef boost::multi_index_container<
                 // than derived class: Lease6.
                 boost::multi_index::member<Lease, uint32_t, &Lease::pool_id_>
             >
+        >,
+
+        // Specification of the eight index starts here.
+        boost::multi_index::ordered_non_unique<
+            boost::multi_index::tag<HWAddressSubnetIdIndexTag>,
+            // 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, const std::vector<uint8_t>&,
+                                                  &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<Lease, SubnetID, &Lease::subnet_id_>
+            >
         >
     >
 > Lease6Storage; // Specify the type name of this container.
@@ -343,6 +364,10 @@ typedef Lease6Storage::index<DuidIaidTypeIndexTag>::type Lease6StorageDuidIaidTy
 /// @brief DHCPv6 lease storage index by expiration time.
 typedef Lease6Storage::index<ExpirationIndexTag>::type Lease6StorageExpirationIndex;
 
+/// @brief DHCPv6 lease storage index by HW address and subnet-id.
+typedef Lease6Storage::index<HWAddressSubnetIdIndexTag>::type
+Lease6StorageHWAddressSubnetIdIndex;
+
 /// @brief DHCPv6 lease storage index by subnet-id.
 typedef Lease6Storage::index<SubnetIdIndexTag>::type Lease6StorageSubnetIdIndex;
 
index ec0286a0d013ecaa572f8e606f3a3ed0b0ef71d2..12b1b17a4f6ae0f52fc63b04b166bcc2f0c57741 100644 (file)
@@ -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.
index 616ca15bf6bfd307dc6fa65a159f3ca1e13ca049..40ea946e4f8f75e49d50d4191d424f3da15f567d 100644 (file)
@@ -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 {
index 0fc468e940464b72a6d36a64531fb7005b26d3fa..19a6ebab53418d0d1c30f72149f805e3828dcd98 100644 (file)
@@ -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
index 20c9865985465af1ef0814c725a1c944fe135b71..008ccaf89f6039c16ff4fb213d18c84e98a5bcf7 100644 (file)
@@ -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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(), 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<uint8_t> invalid(6, 0);
-    returned = lmptr_->getLease4(invalid);
+    HWAddr hwaddr(vector<uint8_t>(6, 0x80), HTYPE_ETHER);
+    hwaddr.hwaddr_ = vector<uint8_t>(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<uint8_t>(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<Lease6Ptr> 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<string> 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<uint8_t>(6, 0x80), HTYPE_ETHER);
+    hwaddr.hwaddr_ = vector<uint8_t>(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<Lease6Ptr> 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
index d1492155e7a83fc0237c52d6257074538bd1cabb..fea4b309a83e9a90f49ea7072a0b2664b390e010 100644 (file)
@@ -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 (file)
index 0000000..b044adb
--- /dev/null
@@ -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 <xref linkend=\"command-lease6-get-by-hw-address\"/>",
+    "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"
+    ]
+}