]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#4441] cfg parsing, allocation state, Mysql bugs
authorThomas Markwalder <tmark@isc.org>
Thu, 9 Apr 2026 19:39:00 +0000 (15:39 -0400)
committerThomas Markwalder <tmark@isc.org>
Fri, 17 Apr 2026 17:21:44 +0000 (17:21 +0000)
Parsing changes so shared-flq allocator can be configured

Added SubnetSflqAllocationState class

MySQL changes:
Added transacations back to lease ops SQL proceduresr
changes in one session were not being committed, so
invisible to others.

Added omitted where parameters to sflqUpdateLease*
Added sflqFakeRowCount() to set affected row count in
lease op procedures

new file:   src/lib/dhcpsrv/sflq_allocation_state.cc
new file:   src/lib/dhcpsrv/sflq_allocation_state.h

/src/bin/admin/tests/mysql_tests.sh.in
    mysql_sflqUpdateLease4()
    mysql_sflqUpdateLease6()
    - added where params:

/src/hooks/dhcp/mysql/mysql_lease_mgr.cc
     MySqlLeaseMgr::SFLQ_UPDATE_LEASE4
     MySqlLeaseMgr::SFLQ_UPDATE_LEASE6
    - added where params:

/src/lib/dhcpsrv/meson.build
    Add sflq_allcoation_state.*

/src/lib/dhcpsrv/parsers/base_network_parser.cc
    BaseNetworkParser::parseAllocatorParams()
    BaseNetworkParser::parsePdAllocatorParams()
    - allow "shared-flg"

/src/lib/dhcpsrv/parsers/shared_network_parser.cc
    SharedNetwork6Parser::parse()
    - disallow shared-flq for NA pools

/src/lib/dhcpsrv/sflq_allocator.*
    SharedFlqAllocator::pickAddressInternal()
    - set last allocated time in subnet allocator state
    SharedFlqAllocator::getSubnetState() - new function

/src/lib/dhcpsrv/subnet.cc
    Subnet4::createAllocators()
    Subnet6::createAllocators()
    - support "shared-flq"

/src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc
    TEST_F(ParseConfigTest, invalidSubnetAllocator4)
    TEST_F(ParseConfigTest, invalidSubnetAllocator6)
    - updated expected error msg

/src/share/database/scripts/mysql/dhcpdb_create.mysql
/src/share/database/scripts/mysql/upgrade_033_to_034.sh.in
    sflqFakeRowCount()
    - new procedure

    sflqInsertLease4
    sflqInsertLease6
    - add back transaction

    sflqUpdateLease4
    sflqUpdateLease6
    - add back transaction
    - preserve affected row count
    - add where params

    sflqDeleteLease4
    sflqDeleteLease6
    - add back transaction
    - preserve affected row count

13 files changed:
src/bin/admin/tests/mysql_tests.sh.in
src/hooks/dhcp/mysql/mysql_lease_mgr.cc
src/lib/dhcpsrv/meson.build
src/lib/dhcpsrv/parsers/base_network_parser.cc
src/lib/dhcpsrv/parsers/shared_network_parser.cc
src/lib/dhcpsrv/sflq_allocation_state.cc [new file with mode: 0644]
src/lib/dhcpsrv/sflq_allocation_state.h [new file with mode: 0644]
src/lib/dhcpsrv/sflq_allocator.cc
src/lib/dhcpsrv/sflq_allocator.h
src/lib/dhcpsrv/subnet.cc
src/lib/dhcpsrv/tests/dhcp_parsers_unittest.cc
src/share/database/scripts/mysql/dhcpdb_create.mysql
src/share/database/scripts/mysql/upgrade_033_to_034.sh.in

index 93da36a6a3788c82937a3e702ed73b3f26d1d93f..8eba6fd9ce34fcf748295f943ce8beefd9ddf2d0 100755 (executable)
@@ -4525,7 +4525,8 @@ mysql_sflqUpdateLease4() {
 
     # Update the lease to declined
     sql="call sflqUpdateLease4(inet_aton($in_address), NULL, NULL, 3600, timestamp('$future'),\
-                               1, 0, 0, NULL, 1, NULL, NULL, NULL, 0)";
+                               1, 0, 0, NULL, 1, NULL, NULL, NULL, 0, inet_aton($in_address),
+                               timestamp('$future'))"
     run_statement "sflqUpdateLease4 $in_address" "$sql"
 
     # Verify lease is updated lease4 and but not present free_lease4
@@ -4536,7 +4537,8 @@ mysql_sflqUpdateLease4() {
 
     # Update the lease to be reclaimed.
     sql="call sflqUpdateLease4(inet_aton($in_address), NULL, NULL, 3600, timestamp('$future'),\
-                               1, 0, 0, NULL, 2, NULL, NULL, NULL, 0)";
+                               1, 0, 0, NULL, 2, NULL, NULL, NULL, 0, inet_aton($in_address),
+                               timestamp('$future'))";
     run_statement "sflqUpdateLease4 to reclaimed $in_address" "$sql"
 
     # Verify lease is updated in lease4 and added to free_lease4
@@ -4561,7 +4563,8 @@ mysql_sflqUpdateLease4() {
 
     # Update the expired lease.
     sql="call sflqUpdateLease4(inet_aton($in_address), NULL, NULL, 3600, timestamp('$expired'),\
-                               1, 0, 0, NULL, 0, NULL, NULL, NULL, 0)";
+                               1, 0, 0, NULL, 0, NULL, NULL, NULL, 0, inet_aton($in_address),
+                               timestamp('$expired'))";
     run_statement "sflqUpdateLease4 update expired $in_address" "$sql"
 
     # Verify lease is updated in lease4 and added to free_lease4
@@ -4796,7 +4799,8 @@ mysql_sflqUpdateLease6() {
     state="1"
     sql="call sflqUpdateLease6($bin_address, $duid, 3600, timestamp('$future'),\
                                $subnet_id, 3600, $ltype, $iaid, 128, 0, 0,\
-                               NULL, NULL, 0, 0, $state, NULL, 0)"
+                               NULL, NULL, 0, 0, $state, NULL, 0,\
+                               $bin_address, timestamp('$future'))"
     run_statement "sflqUpdateLease6 $in_address" "$sql"
 
     # Verify lease is updated lease6 and but not present free_lease6
@@ -4809,7 +4813,8 @@ mysql_sflqUpdateLease6() {
     state="2"
     sql="call sflqUpdateLease6($bin_address, $duid, 3600, timestamp('$future'),\
                                $subnet_id, 3600, $ltype, $iaid, 128, 0, 0,\
-                               NULL, NULL, 0, 0, $state, NULL, 0)"
+                               NULL, NULL, 0, 0, $state, NULL, 0,\
+                               $bin_address, timestamp('$future'))"
     run_statement "sflqUpdateLease6 $in_address" "$sql"
 
     # Verify lease is updated in lease6 and added to free_lease6
@@ -4832,7 +4837,8 @@ mysql_sflqUpdateLease6() {
     state=0
     sql="call sflqUpdateLease6($bin_address, $duid, 3600, timestamp('$expired'),\
                                $subnet_id, 3600, $ltype, $iaid, 128, 0, 0,\
-                               NULL, NULL, 0, 0, $state, NULL, 0)"
+                               NULL, NULL, 0, 0, $state, NULL, 0,\
+                               $bin_address, timestamp('$expired'))"
     run_statement "sflqUpdateLease6 $in_address" "$sql"
 
     # Verify lease is updated in lease6 and added to free_lease6
index e0cdacc34b4fcd1763453e32940cac60df7aaf34..439564e32d23a5fd5f3fddd5eb48d320bb7095d0 100644 (file)
@@ -567,14 +567,14 @@ tagged_statements = { {
                                           "?, ?, ?, ?, ?)"},
     {MySqlLeaseMgr::SFLQ_UPDATE_LEASE4,
                     "CALL sflqUpdateLease4(?, ?, ?, ?, ?, ?, ?, ?, ?, "
-                                          "?, ?, ?, ?, ?)"},
+                                          "?, ?, ?, ?, ?, ?, ?)"},
     {MySqlLeaseMgr::SFLQ_DELETE_LEASE4,
                     "CALL sflqDeleteLease4(?,?)"},
     {MySqlLeaseMgr::SFLQ_INSERT_LEASE6,
                     "CALL sflqInsertLease6(?, ?, ?, ?, ?, ?, ?, ?, ?, "
                                           "?, ?, ?, ?, ?, ?, ?, ?, ?)"},
     {MySqlLeaseMgr::SFLQ_UPDATE_LEASE6,
-                    "CALL sflqUpdateLease6(?, ?, ?, ?, ?, ?, ?, ?, ?, "
+                    "CALL sflqUpdateLease6(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, "
                                           "?, ?, ?, ?, ?, ?, ?, ?, ?)"},
     {MySqlLeaseMgr::SFLQ_DELETE_LEASE6,
                     "CALL sflqDeleteLease6(?, ?)"},
index 202a7a98b4f683f6c01c78adb16fb71a2295ca4a..cc2b7d42c52435afc53441f0c8fa89808e3ae29c 100644 (file)
@@ -79,6 +79,7 @@ sources = [
     'random_allocator.cc',
     'resource_handler.cc',
     'sanity_checker.cc',
+    'sflq_allocation_state.cc',
     'sflq_allocator.cc',
     'shared_network.cc',
     'srv_config.cc',
@@ -208,6 +209,7 @@ kea_dhcpsrv_headers = [
     'random_allocator.h',
     'resource_handler.h',
     'sanity_checker.h',
+    'sflq_allocation_state.h',
     'sflq_allocator.h',
     'shared_network.h',
     'srv_config.h',
index 3c2caa435a5a249c4a0b0d7a5159070c67757a65..f2cfb87faaf2023b3992a3afe40d23dd95069c8d 100644 (file)
@@ -148,9 +148,10 @@ BaseNetworkParser::parseAllocatorParams(const data::ConstElementPtr& network_dat
     if (network_data->contains("allocator")) {
         auto allocator_type = getString(network_data, "allocator");
         if ((allocator_type != "iterative") && (allocator_type != "random") &&
-            (allocator_type != "flq")) {
+            (allocator_type != "flq") && (allocator_type != "shared-flq")) {
             // Unsupported allocator type used.
-            isc_throw(DhcpConfigError, "supported allocators are: iterative, random and flq");
+            isc_throw(DhcpConfigError, "supported allocators are: iterative, "
+                                       "random, flq and shared-flq");
         }
         network->setAllocatorType(allocator_type);
     }
@@ -162,9 +163,10 @@ BaseNetworkParser::parsePdAllocatorParams(const data::ConstElementPtr& network_d
     if (network_data->contains("pd-allocator")) {
         auto allocator_type = getString(network_data, "pd-allocator");
         if ((allocator_type != "iterative") && (allocator_type != "random") &&
-            (allocator_type != "flq")) {
+            (allocator_type != "flq") && (allocator_type != "shared-flq")) {
             // Unsupported allocator type used.
-            isc_throw(DhcpConfigError, "supported allocators are: iterative, random and flq");
+            isc_throw(DhcpConfigError, "supported allocators are: iterative, "
+                                       "random, flq and shared-flq");
         }
         network->setPdAllocatorType(allocator_type);
     }
index 5b8089db5722e0e1af88b240a33782244ba80f3f..ccf57f4b30fb60abbc42996b398d451b1fc2ed5f 100644 (file)
@@ -367,6 +367,12 @@ SharedNetwork6Parser::parse(const data::ConstElementPtr& shared_network_data,
             isc_throw(BadValue, "Free Lease Queue allocator is not supported for IPv6 address pools");
         }
 
+        /// @todo Do we want this or not?  One potential use case would be someone
+        /// using a mapped v4 addresses?  "::xxxx:xxxx" -> "::192.0.2.1"
+        if (network->getAllocatorType() == "shared-flq") {
+            isc_throw(BadValue, "Shared FLQ allocator is not supported for IPv6 address pools");
+        }
+
         // Parse prefix delegation allocator params.
         auto network6 = boost::dynamic_pointer_cast<Network6>(shared_network);
         parsePdAllocatorParams(shared_network_data, network6);
diff --git a/src/lib/dhcpsrv/sflq_allocation_state.cc b/src/lib/dhcpsrv/sflq_allocation_state.cc
new file mode 100644 (file)
index 0000000..8d67e3a
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright (C) 2026 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+#include <dhcpsrv/sflq_allocation_state.h>
+#include <util/multi_threading_mgr.h>
+#include <boost/date_time/posix_time/posix_time.hpp>
+
+using namespace isc::util;
+
+namespace isc {
+namespace dhcp {
+
+SubnetSflqAllocationState::SubnetSflqAllocationState()
+    : SubnetAllocationState() {
+}
+
+void
+SubnetSflqAllocationState::setLastAllocatedTime(boost::posix_time::ptime last_time
+                                            /* = not_a_date_time */) {
+    MultiThreadingLock lock(*mutex_);
+    if (last_time == boost::posix_time::not_a_date_time) {
+        setCurrentAllocatedTimeInternal();
+    } else {
+        last_allocated_time_ = last_time;
+    }
+}
+
+}
+}
diff --git a/src/lib/dhcpsrv/sflq_allocation_state.h b/src/lib/dhcpsrv/sflq_allocation_state.h
new file mode 100644 (file)
index 0000000..4ca7b6a
--- /dev/null
@@ -0,0 +1,67 @@
+// Copyright (C) 2022-2023 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef SFQL_ALLOCATION_STATE_H
+#define SFQL_ALLOCATION_STATE_H
+
+#include <asiolink/io_address.h>
+#include <dhcpsrv/allocation_state.h>
+#include <dhcpsrv/lease.h>
+#include <dhcpsrv/subnet.h>
+#include <boost/shared_ptr.hpp>
+#include <cstdint>
+#include <map>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Forward declaration of the @c SubnetSflqAllocationState.
+class SubnetSflqAllocationState;
+
+/// @brief Type of the pointer to the @c SubnetSflqAllocationState.
+typedef boost::shared_ptr<SubnetSflqAllocationState> SubnetSflqAllocationStatePtr;
+
+/// @brief Subnet allocation state used by the shared-flq allocator.
+///
+/// It exposes the base class mechanism to store the last allocation time
+/// for various lease types. These times are used by the shared networks to 
+/// find the "preferred" subnet (i.e., a subnet from which the latest lease
+/// was assigned).
+class SubnetSflqAllocationState : public SubnetAllocationState {
+public:
+
+#if 0
+    /// @brief Factory function creating the state instance from subnet.
+    ///
+    /// @param subnet instance of the subnet for which the allocation
+    /// state should be instantiated.
+    /// @return new allocation state instance.
+    static SubnetSflqAllocationStatePtr create(const SubnetPtr& subnet);
+#endif
+
+    /// @brief Constructor.
+    ///
+#if 0
+    /// @param prefix subnet prefix.
+    /// @param prefix_length subnet prefix length.
+    SubnetSflqAllocationState(const asiolink::IOAddress& prefix,
+                              const uint8_t prefix_length);
+#else
+    SubnetSflqAllocationState();
+#endif
+
+    /// @brief Set last allocated time.
+    ///
+    /// @param last_time time of last allocation. If not specified
+    /// it is set to the current time.
+    void setLastAllocatedTime(boost::posix_time::ptime last_time = 
+                              boost::posix_time::not_a_date_time);
+};
+
+} // end of namespace isc::dhcp
+} // end of namespace isc
+
+#endif // SFQL_ALLOCATION_STATE_H
index 5b3fa2fef8d72cd8d8541ed03fd8ceb2f3f66e9f..55e4048ca5d3d0e00416bef1c05d0c9e2f06634a 100644 (file)
@@ -109,6 +109,7 @@ SharedFlqAllocator::pickAddressInternal(const ClientClasses& client_classes,
                               .sflqPickFreeLease4(pool->getFirstAddress(),
                                                   pool->getLastAddress());
             if (!free_lease.isV4Zero()) {
+                getSubnetState()->setLastAllocatedTime();
                 return (free_lease);
             }
 
@@ -120,6 +121,7 @@ SharedFlqAllocator::pickAddressInternal(const ClientClasses& client_classes,
                               .sflqPickFreeLease6(pool->getFirstAddress(),
                                                   pool->getLastAddress());
             if (!free_lease.isV6Zero()) {
+                getSubnetState()->setLastAllocatedTime();
                 return (free_lease);
             }
 
@@ -182,6 +184,7 @@ SharedFlqAllocator::pickPrefixInternal(const ClientClasses& client_classes,
                               .sflqPickFreeLease6(pool->getFirstAddress(),
                                                   pool->getLastAddress());
             if (!free_lease.isV6Zero()) {
+                getSubnetState()->setLastAllocatedTime();
                 return (free_lease);
             }
 
@@ -206,5 +209,17 @@ SharedFlqAllocator::getRandomNumber(uint64_t limit) {
     return (dist(generator_));
 }
 
+SubnetSflqAllocationStatePtr
+SharedFlqAllocator::getSubnetState() const {
+    auto subnet = subnet_.lock();
+    if (!subnet->getAllocationState(pool_type_)) {
+        subnet->setAllocationState(Lease::TYPE_V4,
+                                   boost::make_shared<SubnetSflqAllocationState>());
+    }
+
+    return (boost::dynamic_pointer_cast<SubnetSflqAllocationState>
+                                       (subnet->getAllocationState(pool_type_)));
+}
+
 } // end of namespace isc::dhcp
 } // end of namespace isc
index e10dda047528cee247a14b83128e625b5b518af5..b046145d79e142bf301d4e47d74a997e8599cf4f 100644 (file)
@@ -8,6 +8,7 @@
 #define SFLQ_ALLOCATOR_H
 
 #include <dhcpsrv/allocator.h>
+#include <dhcpsrv/sflq_allocation_state.h>
 #include <dhcpsrv/lease.h>
 #include <cstdint>
 
@@ -73,6 +74,11 @@ public:
     /// is using Shared FLQ allocation.
     static bool inUse();
 
+    /// @brief Returns the allocation state for the subnet pool_type;
+    ///
+    /// @return The allocation state.
+    SubnetSflqAllocationStatePtr getSubnetState() const;
+
 private:
 
     /// @brief Performs allocator initialization after server's reconfiguration.
index 9b161196683f34b70331f7d44a7507714a872df7..a46d050f462649eebb640ac19a541fdf2b0158f7 100644 (file)
@@ -16,6 +16,8 @@
 #include <dhcpsrv/iterative_allocator.h>
 #include <dhcpsrv/random_allocation_state.h>
 #include <dhcpsrv/random_allocator.h>
+#include <dhcpsrv/sflq_allocation_state.h>
+#include <dhcpsrv/sflq_allocator.h>
 #include <dhcpsrv/shared_network.h>
 #include <dhcpsrv/subnet.h>
 #include <util/multi_threading_mgr.h>
@@ -776,7 +778,13 @@ Subnet4::createAllocators() {
         for (auto const& pool : pools_) {
             pool->setAllocationState(PoolFreeLeaseQueueAllocationState::create(pool));
         }
-
+    } else if (allocator_type == "shared-flq") {
+        setAllocator(Lease::TYPE_V4,
+                     boost::make_shared<SharedFlqAllocator>
+                     (Lease::TYPE_V4, shared_from_this()));
+        setAllocationState(Lease::TYPE_V4,
+                           boost::make_shared<SubnetSflqAllocationState>());
+        // Does not use pool level allocation states.
     } else {
         setAllocator(Lease::TYPE_V4,
                      boost::make_shared<IterativeAllocator>
@@ -867,7 +875,11 @@ Subnet6::createAllocators() {
                      boost::make_shared<FreeLeaseQueueAllocator>
                      (Lease::TYPE_PD, shared_from_this()));
         setAllocationState(Lease::TYPE_PD, SubnetAllocationStatePtr());
-
+    } else if (allocator_type == "shared-flq") {
+        setAllocator(Lease::TYPE_PD,
+                     boost::make_shared<SharedFlqAllocator>
+                     (Lease::TYPE_PD, shared_from_this()));
+        setAllocationState(Lease::TYPE_PD, SubnetAllocationStatePtr());
     } else {
         setAllocator(Lease::TYPE_PD,
                      boost::make_shared<IterativeAllocator>
index 3eac5244a5f595dddeeaa9f415fb49363aa469f0..5aa21aee6cebdd4834bf94c57e90eee9c2f1c0ea 100644 (file)
@@ -3788,7 +3788,7 @@ TEST_F(ParseConfigTest, invalidSubnetAllocator4) {
     ASSERT_EQ(comment->getType(), Element::string);
     EXPECT_EQ(1, rcode);
     std::string expected = "Configuration parsing failed: ";
-    expected += "supported allocators are: iterative, random and flq";
+    expected += "supported allocators are: iterative, random, flq and shared-flq";
     EXPECT_EQ(expected, comment->stringValue());
 }
 
@@ -3872,7 +3872,7 @@ TEST_F(ParseConfigTest, invalidSubnetAllocator6) {
     ASSERT_EQ(comment->getType(), Element::string);
     EXPECT_EQ(1, rcode);
     std::string expected = "Configuration parsing failed: ";
-    expected += "supported allocators are: iterative, random and flq";
+    expected += "supported allocators are: iterative, random, flq and shared-flq";
     EXPECT_EQ(expected, comment->stringValue());
 }
 
index 38543a5e4ac8f5c6c8b0a92f3f13de83a9ad001c..58c924ac5fca4ad9b39ac2fbb03c25c13677e675 100644 (file)
@@ -7054,6 +7054,24 @@ BEGIN
 END $$
 DELIMITER ;
 
+-- Procedure to create an affected rows count of 1.
+-- Used after udpate and delete lease operations.
+DROP TEMPORARY TABLE IF EXISTS sflq_dummy_row_count;
+DROP PROCEDURE IF EXISTS sflqFakeRowCount;
+DELIMITER $$
+CREATE PROCEDURE sflqFakeRowCount()
+BEGIN
+    IF (@sflq_dummy_exists IS NOT NULL)
+    THEN
+        UPDATE sflq_dummy_row_count SET dummy_val = NOT dummy_val;
+    ELSE
+        SET @sflq_dummy_exists = 1;
+        CREATE TEMPORARY TABLE sflq_dummy_row_count ( dummy_val TINYINT );
+        INSERT INTO sflq_dummy_row_count (dummy_val) VALUES (0);
+    END IF;
+END $$
+DELIMITER ;
+
 -- Procedure to insert a v4 lease and update SFLQ data.
 DROP PROCEDURE IF EXISTS sflqInsertLease4;
 DELIMITER $$
@@ -7073,6 +7091,8 @@ CREATE PROCEDURE sflqInsertLease4(
     IN p_remote_id VARBINARY(255),
     IN p_pool_id INT UNSIGNED)
 BEGIN
+    START TRANSACTION;
+
     INSERT INTO lease4 (address, hwaddr, client_id, valid_lifetime, expire,
                         subnet_id, fqdn_fwd, fqdn_rev, hostname, state,
                         user_context, relay_id, remote_id, pool_id)
@@ -7092,6 +7112,8 @@ BEGIN
         -- Delete it from the free queue. Ignore nothing deleted.
         DELETE FROM free_lease4 WHERE address = p_address;
     END IF;
+
+    COMMIT;
 END $$
 DELIMITER ;
 
@@ -7112,15 +7134,24 @@ CREATE PROCEDURE sflqUpdateLease4(
     IN p_user_context TEXT,
     IN p_relay_id VARBINARY(255),
     IN p_remote_id VARBINARY(255),
-    IN p_pool_id INT UNSIGNED)
+    IN p_pool_id INT UNSIGNED,
+    IN p_where_address INT UNSIGNED,
+    IN p_where_expire TIMESTAMP)
 BEGIN
+    DECLARE lease_row_count INT;
+
+    START TRANSACTION;
+
     UPDATE lease4 SET address = p_address, hwaddr = p_hwaddr, client_id = p_client_id,
                       valid_lifetime = p_valid_lifetime, expire = p_expire,
                       subnet_id = p_subnet_id, fqdn_fwd = p_fqdn_fwd,
                       fqdn_rev = p_fqdn_rev, hostname = p_hostname, state = p_state,
                       user_context = p_user_context, relay_id = p_relay_id,
                       remote_id = p_remote_id, pool_id = p_pool_id
-        WHERE (address = p_address and expire = p_expire);
+        WHERE (address = p_where_address and expire = p_where_expire);
+
+    -- Remember the lease affected row count.
+    SET lease_row_count = row_count();
 
     -- Update SFLQ data.
     -- If it is expired or expired-reclaimed add it to the free lease queue
@@ -7129,11 +7160,20 @@ BEGIN
     THEN
         -- Insert into free queue. Ignore duplicates.
         INSERT INTO free_lease4 (address) VALUES (p_address)
-        ON DUPLICATE KEY UPDATE address = p_address;
+            ON DUPLICATE KEY UPDATE address = p_address;
     ELSE
         -- Delete it from the free queue. Ignore nothing deleted.
         DELETE FROM free_lease4 WHERE address = p_address;
     END IF;
+
+    COMMIT;
+
+    -- If lease was updated but SFLQ logic changed no rows
+    -- force affected row count back to 1.
+    IF (lease_row_count > 0)
+    THEN
+        CALL sflqFakeRowCount();
+    END IF;
 END $$
 DELIMITER ;
 
@@ -7144,18 +7184,33 @@ CREATE PROCEDURE sflqDeleteLease4(
     IN p_address INT UNSIGNED,
     IN p_expire TIMESTAMP)
 BEGIN
+    DECLARE lease_row_count INT;
+
+    START TRANSACTION;
+
     -- Delete the lease from lease4.
     DELETE FROM lease4 WHERE address = p_address AND expire = p_expire;
 
+    -- Remember the lease affected row count.
+    SET lease_row_count = row_count();
+
     -- If we didn't delete it either it was already gone or expire
     -- didn't match. In case of the former it should already be in
     -- the flq and in the latter, it should not be.
     IF (row_count() > 0)
     THEN
-        -- Insert the lease into the free queue. Ignore duplicates.
         INSERT INTO free_lease4 (address) VALUES (p_address)
         ON DUPLICATE KEY UPDATE address = p_address;
     END IF;
+
+    COMMIT;
+
+    -- If the lease was deleted but SFLQ logic changed no rows
+    -- force affected row count back to 1.
+    IF (lease_row_count > 0)
+    THEN
+        CALL sflqFakeRowCount();
+    END IF;
 END $$
 DELIMITER ;
 
@@ -7182,6 +7237,8 @@ CREATE PROCEDURE sflqInsertLease6(
     IN p_user_context TEXT,
     IN p_pool_id INT UNSIGNED)
 BEGIN
+    START TRANSACTION;
+
     INSERT INTO lease6 (address, duid, valid_lifetime, expire, subnet_id,
                         pref_lifetime, lease_type, iaid, prefix_len,
                         fqdn_fwd, fqdn_rev, hostname, hwaddr, hwtype,
@@ -7204,6 +7261,8 @@ BEGIN
         -- Delete it from the free queue. Ignore nothing deleted.
         DELETE FROM free_lease6 WHERE bin_address = p_address;
     END IF;
+
+    COMMIT;
 END $$
 DELIMITER ;
 
@@ -7228,15 +7287,24 @@ CREATE PROCEDURE sflqUpdateLease6(
     IN p_hwaddr_source INT UNSIGNED,
     IN p_state INT UNSIGNED,
     IN p_user_context TEXT,
-    IN p_pool_id INT UNSIGNED)
+    IN p_pool_id INT UNSIGNED,
+    IN p_where_address BINARY(16),
+    IN p_where_expire TIMESTAMP)
 BEGIN
+    DECLARE lease_row_count INT;
+
+    START TRANSACTION;
+
     UPDATE lease6 SET address = p_address, duid = p_duid, valid_lifetime = p_valid_lifetime,
                       expire = p_expire, subnet_id = p_subnet_id, pref_lifetime = p_pref_lifetime,
                       lease_type = p_lease_type, iaid = p_iaid, prefix_len = p_prefix_len,
                       fqdn_fwd = p_fqdn_fwd, fqdn_rev = p_fqdn_rev, hostname = p_hostname,
                       hwaddr = p_hwaddr, hwtype = p_hwtype, hwaddr_source = p_hwaddr_source,
                       state = p_state, user_context = p_user_context, pool_id = p_pool_id
-        WHERE (address = p_address and expire = p_expire);
+        WHERE (address = p_where_address and expire = p_where_expire);
+
+    -- Remember the lease affected row count.
+    SET lease_row_count = row_count();
 
     -- Update SFLQ data.
     -- If it is expired or expired-reclaimed add it to the free lease queue
@@ -7251,6 +7319,15 @@ BEGIN
         -- Delete it from the free queue. Ignore nothing deleted.
         DELETE FROM free_lease6 WHERE bin_address = p_address;
     END IF;
+
+    COMMIT;
+
+    -- If lease was updated but SFLQ logic changed no rows
+    -- force affected row count back to 1.
+    IF (lease_row_count > 0)
+    THEN
+        CALL sflqFakeRowCount();
+    END IF;
 END $$
 DELIMITER ;
 
@@ -7261,9 +7338,16 @@ CREATE PROCEDURE sflqDeleteLease6(
     IN p_address BINARY(16),
     IN p_expire TIMESTAMP)
 BEGIN
+    DECLARE lease_row_count INT;
+
+    START TRANSACTION;
+
     -- Delete the lease from lease4.
     DELETE FROM lease6 WHERE address = p_address AND expire = p_expire;
 
+    -- Remember the lease affected row count.
+    SET lease_row_count = row_count();
+
     -- If we didn't delete it either it was already gone or expire
     -- didn't match. In case of the former it should already be in
     -- the flq and in the latter, it should not be.
@@ -7274,6 +7358,15 @@ BEGIN
             VALUES (INET6_NTOA(p_address), p_address)
         ON DUPLICATE KEY UPDATE bin_address = p_address;
     END IF;
+
+    COMMIT;
+
+    -- If the lease was deleted but SFLQ logic changed no rows
+    -- force affected row count back to 1.
+    IF (lease_row_count > 0)
+    THEN
+        CALL sflqFakeRowCount();
+    END IF;
 END $$
 DELIMITER ;
 
index a683285bc28face8c5b0accba96369edd10ecb2f..4af4a0fd7e6b0b53b5ac701cff335e7d8f3963f0 100755 (executable)
@@ -635,6 +635,24 @@ BEGIN
 END $$
 DELIMITER ;
 
+-- Procedure to create an affected rows count of 1.
+-- Used after udpate and delete lease operations.
+DROP TEMPORARY TABLE IF EXISTS sflq_dummy_row_count;
+DROP PROCEDURE IF EXISTS sflqFakeRowCount;
+DELIMITER $$
+CREATE PROCEDURE sflqFakeRowCount()
+BEGIN
+    IF (@sflq_dummy_exists IS NOT NULL)
+    THEN
+        UPDATE sflq_dummy_row_count SET dummy_val = NOT dummy_val;
+    ELSE
+        SET @sflq_dummy_exists = 1;
+        CREATE TEMPORARY TABLE sflq_dummy_row_count ( dummy_val TINYINT );
+        INSERT INTO sflq_dummy_row_count (dummy_val) VALUES (0);
+    END IF;
+END $$
+DELIMITER ;
+
 -- Procedure to insert a v4 lease and update SFLQ data.
 DROP PROCEDURE IF EXISTS sflqInsertLease4;
 DELIMITER $$
@@ -654,6 +672,8 @@ CREATE PROCEDURE sflqInsertLease4(
     IN p_remote_id VARBINARY(255),
     IN p_pool_id INT UNSIGNED)
 BEGIN
+    START TRANSACTION;
+
     INSERT INTO lease4 (address, hwaddr, client_id, valid_lifetime, expire,
                         subnet_id, fqdn_fwd, fqdn_rev, hostname, state,
                         user_context, relay_id, remote_id, pool_id)
@@ -673,6 +693,8 @@ BEGIN
         -- Delete it from the free queue. Ignore nothing deleted.
         DELETE FROM free_lease4 WHERE address = p_address;
     END IF;
+
+    COMMIT;
 END $$
 DELIMITER ;
 
@@ -693,15 +715,24 @@ CREATE PROCEDURE sflqUpdateLease4(
     IN p_user_context TEXT,
     IN p_relay_id VARBINARY(255),
     IN p_remote_id VARBINARY(255),
-    IN p_pool_id INT UNSIGNED)
+    IN p_pool_id INT UNSIGNED,
+    IN p_where_address INT UNSIGNED,
+    IN p_where_expire TIMESTAMP)
 BEGIN
+    DECLARE lease_row_count INT;
+
+    START TRANSACTION;
+
     UPDATE lease4 SET address = p_address, hwaddr = p_hwaddr, client_id = p_client_id,
                       valid_lifetime = p_valid_lifetime, expire = p_expire,
                       subnet_id = p_subnet_id, fqdn_fwd = p_fqdn_fwd,
                       fqdn_rev = p_fqdn_rev, hostname = p_hostname, state = p_state,
                       user_context = p_user_context, relay_id = p_relay_id,
                       remote_id = p_remote_id, pool_id = p_pool_id
-        WHERE (address = p_address and expire = p_expire);
+        WHERE (address = p_where_address and expire = p_where_expire);
+
+    -- Remember the lease affected row count.
+    SET lease_row_count = row_count();
 
     -- Update SFLQ data.
     -- If it is expired or expired-reclaimed add it to the free lease queue
@@ -710,11 +741,20 @@ BEGIN
     THEN
         -- Insert into free queue. Ignore duplicates.
         INSERT INTO free_lease4 (address) VALUES (p_address)
-        ON DUPLICATE KEY UPDATE address = p_address;
+            ON DUPLICATE KEY UPDATE address = p_address;
     ELSE
         -- Delete it from the free queue. Ignore nothing deleted.
         DELETE FROM free_lease4 WHERE address = p_address;
     END IF;
+
+    COMMIT;
+
+    -- If lease was updated but SFLQ logic changed no rows
+    -- force affected row count back to 1.
+    IF (lease_row_count > 0)
+    THEN
+        CALL sflqFakeRowCount();
+    END IF;
 END $$
 DELIMITER ;
 
@@ -725,18 +765,33 @@ CREATE PROCEDURE sflqDeleteLease4(
     IN p_address INT UNSIGNED,
     IN p_expire TIMESTAMP)
 BEGIN
+    DECLARE lease_row_count INT;
+
+    START TRANSACTION;
+
     -- Delete the lease from lease4.
     DELETE FROM lease4 WHERE address = p_address AND expire = p_expire;
 
+    -- Remember the lease affected row count.
+    SET lease_row_count = row_count();
+
     -- If we didn't delete it either it was already gone or expire
     -- didn't match. In case of the former it should already be in
     -- the flq and in the latter, it should not be.
     IF (row_count() > 0)
     THEN
-        -- Insert the lease into the free queue. Ignore duplicates.
         INSERT INTO free_lease4 (address) VALUES (p_address)
         ON DUPLICATE KEY UPDATE address = p_address;
     END IF;
+
+    COMMIT;
+
+    -- If the lease was deleted but SFLQ logic changed no rows
+    -- force affected row count back to 1.
+    IF (lease_row_count > 0)
+    THEN
+        CALL sflqFakeRowCount();
+    END IF;
 END $$
 DELIMITER ;
 
@@ -763,6 +818,8 @@ CREATE PROCEDURE sflqInsertLease6(
     IN p_user_context TEXT,
     IN p_pool_id INT UNSIGNED)
 BEGIN
+    START TRANSACTION;
+
     INSERT INTO lease6 (address, duid, valid_lifetime, expire, subnet_id,
                         pref_lifetime, lease_type, iaid, prefix_len,
                         fqdn_fwd, fqdn_rev, hostname, hwaddr, hwtype,
@@ -785,6 +842,8 @@ BEGIN
         -- Delete it from the free queue. Ignore nothing deleted.
         DELETE FROM free_lease6 WHERE bin_address = p_address;
     END IF;
+
+    COMMIT;
 END $$
 DELIMITER ;
 
@@ -809,15 +868,24 @@ CREATE PROCEDURE sflqUpdateLease6(
     IN p_hwaddr_source INT UNSIGNED,
     IN p_state INT UNSIGNED,
     IN p_user_context TEXT,
-    IN p_pool_id INT UNSIGNED)
+    IN p_pool_id INT UNSIGNED,
+    IN p_where_address BINARY(16),
+    IN p_where_expire TIMESTAMP)
 BEGIN
+    DECLARE lease_row_count INT;
+
+    START TRANSACTION;
+
     UPDATE lease6 SET address = p_address, duid = p_duid, valid_lifetime = p_valid_lifetime,
                       expire = p_expire, subnet_id = p_subnet_id, pref_lifetime = p_pref_lifetime,
                       lease_type = p_lease_type, iaid = p_iaid, prefix_len = p_prefix_len,
                       fqdn_fwd = p_fqdn_fwd, fqdn_rev = p_fqdn_rev, hostname = p_hostname,
                       hwaddr = p_hwaddr, hwtype = p_hwtype, hwaddr_source = p_hwaddr_source,
                       state = p_state, user_context = p_user_context, pool_id = p_pool_id
-        WHERE (address = p_address and expire = p_expire);
+        WHERE (address = p_where_address and expire = p_where_expire);
+
+    -- Remember the lease affected row count.
+    SET lease_row_count = row_count();
 
     -- Update SFLQ data.
     -- If it is expired or expired-reclaimed add it to the free lease queue
@@ -832,6 +900,15 @@ BEGIN
         -- Delete it from the free queue. Ignore nothing deleted.
         DELETE FROM free_lease6 WHERE bin_address = p_address;
     END IF;
+
+    COMMIT;
+
+    -- If lease was updated but SFLQ logic changed no rows
+    -- force affected row count back to 1.
+    IF (lease_row_count > 0)
+    THEN
+        CALL sflqFakeRowCount();
+    END IF;
 END $$
 DELIMITER ;
 
@@ -842,9 +919,16 @@ CREATE PROCEDURE sflqDeleteLease6(
     IN p_address BINARY(16),
     IN p_expire TIMESTAMP)
 BEGIN
+    DECLARE lease_row_count INT;
+
+    START TRANSACTION;
+
     -- Delete the lease from lease4.
     DELETE FROM lease6 WHERE address = p_address AND expire = p_expire;
 
+    -- Remember the lease affected row count.
+    SET lease_row_count = row_count();
+
     -- If we didn't delete it either it was already gone or expire
     -- didn't match. In case of the former it should already be in
     -- the flq and in the latter, it should not be.
@@ -855,6 +939,15 @@ BEGIN
             VALUES (INET6_NTOA(p_address), p_address)
         ON DUPLICATE KEY UPDATE bin_address = p_address;
     END IF;
+
+    COMMIT;
+
+    -- If the lease was deleted but SFLQ logic changed no rows
+    -- force affected row count back to 1.
+    IF (lease_row_count > 0)
+    THEN
+        CALL sflqFakeRowCount();
+    END IF;
 END $$
 DELIMITER ;