]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#4466] Added new SFLQ API funcs to PgSqlLeaseMgr
authorThomas Markwalder <tmark@isc.org>
Fri, 24 Apr 2026 19:48:49 +0000 (15:48 -0400)
committerThomas Markwalder <tmark@isc.org>
Mon, 4 May 2026 15:32:33 +0000 (15:32 +0000)
/src/hooks/dhcp/pgsql/pgsql_lb_messages.*
    PGSQL_LB_SFLQ_POOL4_GET_ALL
    PGSQL_LB_SFLQ_POOL4_GET_BY_SUBNET
    PGSQL_LB_SFLQ_POOL4_GET_BY_RANGE
    PGSQL_LB_SFLQ_POOL4_DELETE delete
    PGSQL_LB_SFLQ_POOL6_GET_ALL fetch
    PGSQL_LB_SFLQ_POOL6_GET_BY_SUBNET
    PGSQL_LB_SFLQ_POOL6_GET_BY_RANGE
    PGSQL_LB_SFLQ_POOL6_DELETE
    - new messages

/src/hooks/dhcp/pgsql/pgsql_lease_mgr.cc
    PgSqlLeaseMgr::SFLQ_POOL4_GET_ALL
    PgSqlLeaseMgr::SFLQ_POOL4_GET_BY_SUBNET
    PgSqlLeaseMgr::SFLQ_POOL4_GET_BY_RANGE
    PgSqlLeaseMgr::SFLQ_POOL4_DELETE
    PgSqlLeaseMgr::SFLQ_POOL6_GET_ALL
    PgSqlLeaseMgr::SFLQ_POOL6_GET_BY_SUBNET
    PgSqlLeaseMgr::SFLQ_POOL6_GET_BY_RANGE
    PgSqlLeaseMgr::SFLQ_POOL6_DELETE
    - new SQL statements

    PgSqlLeaseMgr::sflqCreateFlqPool4()
    PgSqlLeaseMgr::sflqPickFreeLease4()
    PgSqlLeaseMgr::sflqCreateFlqPool6()
    PgSqlLeaseMgr::sflqPickFreeLease6()
    - added range adddress validation

    PgSqlLeaseMgr::sflqPool4GetAll()
    PgSqlLeaseMgr::sflqPool4Get(*)
    PgSqlLeaseMgr::sflqPool4Del()
    PgSqlLeaseMgr::sflqPool6GetAll()
    PgSqlLeaseMgr::sflqPool6Get(*)
    PgSqlLeaseMgr::sflqPool6Del()
    PgSqlLeaseMgr::sflqPoolGetCommon()
    PgSqlLeaseMgr::sflqPoolDelCommon()
    - new functions

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

index bd5d8753cb810071c718fde3371665aba1b2d013..2d926f0081898f1a3ddc509eb41821873264c3ea 100644 (file)
@@ -58,6 +58,14 @@ extern const isc::log::MessageID PGSQL_LB_SFLQ_CREATE_POOL4 = "PGSQL_LB_SFLQ_CRE
 extern const isc::log::MessageID PGSQL_LB_SFLQ_CREATE_POOL6 = "PGSQL_LB_SFLQ_CREATE_POOL6";
 extern const isc::log::MessageID PGSQL_LB_SFLQ_PICK_LEASE4 = "PGSQL_LB_SFLQ_PICK_LEASE4";
 extern const isc::log::MessageID PGSQL_LB_SFLQ_PICK_LEASE6 = "PGSQL_LB_SFLQ_PICK_LEASE6";
+extern const isc::log::MessageID PGSQL_LB_SFLQ_POOL4_DELETE = "PGSQL_LB_SFLQ_POOL4_DELETE";
+extern const isc::log::MessageID PGSQL_LB_SFLQ_POOL4_GET_ALL = "PGSQL_LB_SFLQ_POOL4_GET_ALL";
+extern const isc::log::MessageID PGSQL_LB_SFLQ_POOL4_GET_BY_RANGE = "PGSQL_LB_SFLQ_POOL4_GET_BY_RANGE";
+extern const isc::log::MessageID PGSQL_LB_SFLQ_POOL4_GET_BY_SUBNET = "PGSQL_LB_SFLQ_POOL4_GET_BY_SUBNET";
+extern const isc::log::MessageID PGSQL_LB_SFLQ_POOL6_DELETE = "PGSQL_LB_SFLQ_POOL6_DELETE";
+extern const isc::log::MessageID PGSQL_LB_SFLQ_POOL6_GET_ALL = "PGSQL_LB_SFLQ_POOL6_GET_ALL";
+extern const isc::log::MessageID PGSQL_LB_SFLQ_POOL6_GET_BY_RANGE = "PGSQL_LB_SFLQ_POOL6_GET_BY_RANGE";
+extern const isc::log::MessageID PGSQL_LB_SFLQ_POOL6_GET_BY_SUBNET = "PGSQL_LB_SFLQ_POOL6_GET_BY_SUBNET";
 extern const isc::log::MessageID PGSQL_LB_UPDATE_ADDR4 = "PGSQL_LB_UPDATE_ADDR4";
 extern const isc::log::MessageID PGSQL_LB_UPDATE_ADDR6 = "PGSQL_LB_UPDATE_ADDR6";
 extern const isc::log::MessageID PGSQL_LB_UPGRADE_EXTENDED_INFO4 = "PGSQL_LB_UPGRADE_EXTENDED_INFO4";
@@ -124,6 +132,14 @@ const char* values[] = {
     "PGSQL_LB_SFLQ_CREATE_POOL6", "creating shared-flq pool for address range %1 - %2, type %3, delegated length: %4, subnet id %5, recreate %6, capacity %7",
     "PGSQL_LB_SFLQ_PICK_LEASE4", "picking a free lease from address range %1 - %2",
     "PGSQL_LB_SFLQ_PICK_LEASE6", "picking a free lease from address range %1 - %2",
+    "PGSQL_LB_SFLQ_POOL4_DELETE", "delete the V4 SFLQ pool with start address %1 and end address %2, forece = %3",
+    "PGSQL_LB_SFLQ_POOL4_GET_ALL", "fetch all V4 SFLQ pools",
+    "PGSQL_LB_SFLQ_POOL4_GET_BY_RANGE", "fetch all V4 SFLQ pools that overlap the range %1 and %2",
+    "PGSQL_LB_SFLQ_POOL4_GET_BY_SUBNET", "fetch all V4 SFLQ pools for subnet-id %1",
+    "PGSQL_LB_SFLQ_POOL6_DELETE", "delete the V6 SFLQ pool with start address %1 and end address %2, forece = %3",
+    "PGSQL_LB_SFLQ_POOL6_GET_ALL", "fetch all V6 SFLQ pools",
+    "PGSQL_LB_SFLQ_POOL6_GET_BY_RANGE", "fetch all V6 SFLQ pools that overlap the range %1 and %2",
+    "PGSQL_LB_SFLQ_POOL6_GET_BY_SUBNET", "fetch all V6 SFLQ pools for subnet-id %1",
     "PGSQL_LB_UPDATE_ADDR4", "updating IPv4 lease for address %1",
     "PGSQL_LB_UPDATE_ADDR6", "updating IPv6 lease for address %1, lease type %2",
     "PGSQL_LB_UPGRADE_EXTENDED_INFO4", "upgrading IPv4 leases done in %1 pages with %2 updated leases",
index d24be380208b43be87e8141aa57ae765d69fbbc7..ee4ea45a6bfcb101f0f124ad3dea79166646f8b4 100644 (file)
@@ -59,6 +59,14 @@ extern const isc::log::MessageID PGSQL_LB_SFLQ_CREATE_POOL4;
 extern const isc::log::MessageID PGSQL_LB_SFLQ_CREATE_POOL6;
 extern const isc::log::MessageID PGSQL_LB_SFLQ_PICK_LEASE4;
 extern const isc::log::MessageID PGSQL_LB_SFLQ_PICK_LEASE6;
+extern const isc::log::MessageID PGSQL_LB_SFLQ_POOL4_DELETE;
+extern const isc::log::MessageID PGSQL_LB_SFLQ_POOL4_GET_ALL;
+extern const isc::log::MessageID PGSQL_LB_SFLQ_POOL4_GET_BY_RANGE;
+extern const isc::log::MessageID PGSQL_LB_SFLQ_POOL4_GET_BY_SUBNET;
+extern const isc::log::MessageID PGSQL_LB_SFLQ_POOL6_DELETE;
+extern const isc::log::MessageID PGSQL_LB_SFLQ_POOL6_GET_ALL;
+extern const isc::log::MessageID PGSQL_LB_SFLQ_POOL6_GET_BY_RANGE;
+extern const isc::log::MessageID PGSQL_LB_SFLQ_POOL6_GET_BY_SUBNET;
 extern const isc::log::MessageID PGSQL_LB_UPDATE_ADDR4;
 extern const isc::log::MessageID PGSQL_LB_UPDATE_ADDR6;
 extern const isc::log::MessageID PGSQL_LB_UPGRADE_EXTENDED_INFO4;
index a62aea5045b8750f0aeac9f17dfa54c7402f3f5d..26db35ed0f38999088e59f03c685fc2c7e8231b2 100644 (file)
@@ -320,3 +320,65 @@ Logged at debug log level 50.
 This debug message is issued when the server upgrades IPv6 lease extended info.
 The page number and started address, and the count of already updated leases
 are displayed.
+
+% PGSQL_LB_SFLQ_CREATE_POOL4 creating shared-flq pool for address range %1 - %2, subnet id %3, recreate %4, capacity %5
+Logged at debug log level 50.
+This debug message is issued when the server asks the lease back end to
+(re)create the shared free lease data for the pool described in the arguments.
+
+% PGSQL_LB_SFLQ_PICK_LEASE4 picking a free lease from address range %1 - %2
+Logged at debug log level 50.
+This debug message is issued when the server asks the lease back end for
+a free address from the pool described in the arguments.
+
+% PGSQL_LB_SFLQ_CREATE_POOL6 creating shared-flq pool for address range %1 - %2, type %3, delegated length: %4, subnet id %5, recreate %6, capacity %7
+Logged at debug log level 50.
+This debug message is issued when the server asks the lease back end to
+(re)create the shared free lease data for the pool described in the arguments.
+
+% PGSQL_LB_SFLQ_PICK_LEASE6 picking a free lease from address range %1 - %2
+Logged at debug log level 50.
+This debug message is issued when the server asks the lease back end for
+a free lease from the pool described in the arguments.
+
+% PGSQL_LB_SFLQ_POOL4_GET_ALL fetch all V4 SFLQ pools
+Logged at debug log level 50.
+This debug message is issued when the server asks the lease back end for
+a list of all v4 SFLQ pools.
+
+% PGSQL_LB_SFLQ_POOL4_GET_BY_SUBNET fetch all V4 SFLQ pools for subnet-id %1
+Logged at debug log level 50.
+This debug message is issued when the server asks the lease back end for
+a list of all v4 SFLQ pools belonging to a subnet.
+
+% PGSQL_LB_SFLQ_POOL4_GET_BY_RANGE fetch all V4 SFLQ pools that overlap the range %1 and %2
+Logged at debug log level 50.
+This debug message is issued when the server asks the lease back end for
+the v4 SFLQ pool that overlap the given address range.
+
+% PGSQL_LB_SFLQ_POOL4_DELETE delete the V4 SFLQ pool with start address %1 and end address %2, forece = %3
+Logged at debug log level 50.
+This debug message is issued when the server asks the lease back to delete
+the v4 SFLQ pool (and it's free lease data) that match the given start and end
+addresses.
+
+% PGSQL_LB_SFLQ_POOL6_GET_ALL fetch all V6 SFLQ pools
+Logged at debug log level 50.
+This debug message is issued when the server asks the lease back end for
+a list of all v6 SFLQ pools.
+
+% PGSQL_LB_SFLQ_POOL6_GET_BY_SUBNET fetch all V6 SFLQ pools for subnet-id %1
+Logged at debug log level 50.
+This debug message is issued when the server asks the lease back end for
+a list of all v6 SFLQ pools belonging to a subnet.
+
+% PGSQL_LB_SFLQ_POOL6_GET_BY_RANGE fetch all V6 SFLQ pools that overlap the range %1 and %2
+Logged at debug log level 50.
+This debug message is issued when the server asks the lease back end for
+the v6 SFLQ pool that overlap the given address range.
+
+% PGSQL_LB_SFLQ_POOL6_DELETE delete the V6 SFLQ pool with start address %1 and end address %2, forece = %3
+Logged at debug log level 50.
+This debug message is issued when the server asks the lease back to delete
+the v6 SFLQ pool (and it's free lease data) that match the given start and end
+addresses
index 7b17fc3680be0f5eef93ab5b3d79fae6e3cfb81e..68beaa7a0531555f2f40caca92ede49bb3f48268 100644 (file)
@@ -752,6 +752,133 @@ PgSqlTaggedStatement tagged_statements[] = {
       "sflqDeleteLease6",
       "SELECT sflqDeleteLease6(cast($1 as inet), $2)" },
 
+    // SFLQ_SFLQ_POOL4_GET_ALL
+    { 0, { },
+      "sflqPool4GetAll",
+      "SELECT q.id, q.subnet_id, 3 as lease_type, "
+      "       q.start_address, q.end_address, 128 as delegated_len, "
+      "       gmt_epoch(q.created_ts) as created_ts, "
+      "       gmt_epoch(q.modification_ts) as modification_ts, "
+      "       count(f.address) as free_leases "
+      "    FROM flq_pool4 AS q "
+      "    LEFT JOIN free_lease4 AS f "
+      "    ON f.address >= q.start_address AND f.address <= q.end_address "
+      "    GROUP BY q.id "
+      "    ORDER BY q.subnet_id, q.start_address"},
+
+    // SFLQ_SFLQ_POOL4_GET_BY_SUBNET
+    { 1, { OID_INT8 },
+      "sflqPool4GetBySubnet",
+      "SELECT q.id, q.subnet_id, 3 as lease_type, "
+      "       q.start_address, q.end_address, 128 as delegated_len, "
+      "       gmt_epoch(q.created_ts) as created_ts, "
+      "       gmt_epoch(q.modification_ts) as modification_ts, "
+      "       count(f.address) as free_leases "
+      "    FROM flq_pool4 AS q "
+      "    LEFT JOIN free_lease4 AS f "
+      "    ON f.address >= q.start_address AND f.address <= q.end_address "
+      "    WHERE q.subnet_id = $1 "
+      "    GROUP BY q.id "
+      "    ORDER BY q.subnet_id, q.start_address"},
+
+    // SFLQ_POOL4_GET_BY_RANGE
+    { 2, { OID_INT8, OID_INT8 },
+      "sflqPool4GetByRange",
+      "SELECT q.id, q.subnet_id, 3 as lease_type, "
+      "       q.start_address, q.end_address, 128 as delegated_len, "
+      "       gmt_epoch(q.created_ts) as created_ts, "
+      "       gmt_epoch(q.modification_ts) as modification_ts, "
+      "       count(f.address) as free_leases "
+      "    FROM flq_pool4 AS q "
+      "    LEFT JOIN free_lease4 AS f "
+      "    ON f.address >= q.start_address AND f.address <= q.end_address "
+      //    WHERE ((q.start <= p_start AND p_start <= q.end) OR "
+      //           (q.start <= p_end AND p_pend <= q.end) OR "
+      //           (p_start < q.start AND q.end < p_end))
+      "    WHERE ((q.start_address <= $1 AND $1 <= q.end_address) OR "
+      "           (q.start_address <= $2 AND $2 <= q.end_address) OR "
+      "           ($1 < q.start_address AND q.end_address < $2)) "
+      "    GROUP BY q.id "
+      "    ORDER BY q.subnet_id ASC, q.start_address ASC"},
+
+    // SFLQ_POOL4_DEL
+    { 2, { OID_INT8, OID_INT8 },
+      "sflqPool4GetDel",
+      "WITH deleted_pool AS ( "
+      "    DELETE FROM flq_pool4 "
+      "    WHERE start_address = $1 "
+      "      AND end_address = $2 "
+      "    RETURNING start_address, end_address) "
+      "DELETE FROM free_lease4 f "
+      "     USING deleted_pool p "
+      "     WHERE f.address BETWEEN p.start_address AND p.end_address"},
+
+    // SFLQ_SFLQ_POOL6_GET_ALL
+    { 0, { },
+      "sflqPool6GetAll",
+      "SELECT q.id, q.subnet_id, q.lease_type, "
+      "       q.start_address, q.end_address, q.delegated_len, "
+      "       gmt_epoch(q.created_ts) as created_ts, "
+      "       gmt_epoch(q.modification_ts) as modification_ts, "
+      "       count(f.address) as free_leases "
+      "    FROM flq_pool6 AS q "
+      "    LEFT JOIN free_lease6 AS f "
+      "    ON f.bin_address >= inetToBytea(q.start_address) AND "
+      "       f.bin_address <= inetToBytea(q.end_address) "
+      "    GROUP BY q.id "
+      "    ORDER BY q.subnet_id ASC, inetToBytea(q.start_address) ASC "},
+
+    // SFLQ_SFLQ_POOL6_GET_BY_SUBNET
+    { 1, { OID_INT8 },
+      "sflqPool6GetBySubnet",
+      "SELECT q.id, q.subnet_id, q.lease_type, "
+      "       q.start_address, q.end_address, q.delegated_len, "
+      "       gmt_epoch(q.created_ts) as created_ts, "
+      "       gmt_epoch(q.modification_ts) as modification_ts, "
+      "       count(f.address) as free_leases "
+      "    FROM flq_pool6 AS q "
+      "    LEFT JOIN free_lease6 AS f "
+      "    ON f.bin_address >= inetToBytea(q.start_address) AND "
+      "       f.bin_address <= inetToBytea(q.end_address) "
+      "    WHERE q.subnet_id = $1 "
+      "    GROUP BY q.id "
+      "    ORDER BY q.subnet_id ASC, inetToBytea(q.start_address) ASC "},
+
+    // SFLQ_POOL6_GET_BY_RANGE
+    { 2, { OID_VARCHAR, OID_VARCHAR },
+      "sflqPool6GetByRange",
+      "SELECT q.id, q.subnet_id, q.lease_type, "
+      "       q.start_address, q.end_address, q.delegated_len, "
+      "       gmt_epoch(q.created_ts) as created_ts, "
+      "       gmt_epoch(q.modification_ts) as modification_ts, "
+      "       count(f.address) as free_leases "
+      "    FROM flq_pool6 AS q "
+      "    LEFT JOIN free_lease6 AS f "
+      "    ON f.address >= q.start_address AND f.address <= q.end_address "
+      //    WHERE ((q.start <= p_start AND p_start <= q.end) OR "
+      //           (q.start <= p_end AND p_pend <= q.end) OR "
+      //           (p_start < q.start AND q.end < p_end))
+      "    WHERE ((inetToBytea(q.start_address) <= inetToBytea($1::inet) "
+      "            AND inetToBytea($1::inet) <= inetToBytea(q.end_address)) OR"
+      "           (inetToBytea(q.start_address) <= inetToBytea($2::inet) AND "
+      "            inetToBytea($2::inet) <= inetToBytea(q.end_address)) OR "
+      "           (inetToBytea($1::inet) < inetToBytea(q.start_address) AND "
+      "           inetToBytea(q.end_address) < inetToBytea($2::inet))) "
+      "    GROUP BY q.id "
+      "    ORDER BY q.subnet_id ASC, q.start_address ASC"},
+
+    // SFLQ_POOL6_DEL
+    { 2, { OID_VARCHAR, OID_VARCHAR },
+      "sflqPool6GetDel",
+      "WITH deleted_pool AS ( "
+      "    DELETE FROM flq_pool6 "
+      "    WHERE start_address = $1::inet "
+      "      AND end_address = $2::inet "
+      "    RETURNING start_address, end_address) "
+      "DELETE FROM free_lease6 f "
+      "     USING deleted_pool p "
+      "     WHERE f.bin_address BETWEEN inetToBytea(p.start_address) "
+      "                             AND inetToBytea(p.end_address)"},
     // End of list sentinel
     { 0, { 0 }, 0, 0 }
 };
@@ -4011,19 +4138,24 @@ PgSqlLeaseMgr::byRemoteId6size() const {
 bool
 PgSqlLeaseMgr::sflqCreateFlqPool4(IOAddress start_address, IOAddress end_address,
                                   SubnetID subnet_id, bool recreate) {
-    auto capacity = addrsInRange(start_address, end_address);
-    LOG_DEBUG(pgsql_lb_logger, PGSQL_LB_DBG_TRACE_DETAIL, PGSQL_LB_SFLQ_CREATE_POOL4)
-        .arg(start_address.toText())
-        .arg(end_address.toText())
-        .arg(subnet_id)
-        .arg(recreate)
-        .arg(capacity);
-
-    if (capacity > SharedFlqAllocator::MAX_V4_POOL_SIZE) {
-        isc_throw(BadValue, "PgSqlLeasMgr::sflqCreateFlqPool4 pool capacity "
-                            << capacity << " exceeds limit of "
+    // This is clunky but it allows us to log the capacity.
+    try {
+        validateV4Range(start_address, end_address);
+        auto capacity = addrsInRange(start_address, end_address);
+        if (capacity > SharedFlqAllocator::MAX_V4_POOL_SIZE) {
+            isc_throw(BadValue, "pool capacity " << capacity << " exceeds limit of "
                             << SharedFlqAllocator::MAX_V4_POOL_SIZE
                             << " for shared-flq allocator on V4 pool ");
+        }
+
+        LOG_DEBUG(pgsql_lb_logger, PGSQL_LB_DBG_TRACE_DETAIL, PGSQL_LB_SFLQ_CREATE_POOL4)
+            .arg(start_address.toText())
+            .arg(end_address.toText())
+            .arg(subnet_id)
+            .arg(recreate)
+            .arg(capacity);
+    } catch (const std::exception& ex) {
+        isc_throw(BadValue, "PgqlLeasMgr::sflqCreateFlqPool4 " << ex.what());
     }
 
     // Get a context
@@ -4066,6 +4198,8 @@ PgSqlLeaseMgr::sflqPickFreeLease4(IOAddress start_address, IOAddress end_address
         .arg(start_address.toText())
         .arg(end_address.toText());
 
+    validateV4Range(start_address, end_address);
+
     // Get a context
     PgSqlLeaseContextAlloc get_context(*this);
     PgSqlLeaseContextPtr ctx = get_context.ctx_;
@@ -4107,28 +4241,27 @@ bool
 PgSqlLeaseMgr::sflqCreateFlqPool6(IOAddress start_address, IOAddress end_address,
                                   Lease::Type lease_type, uint8_t delegated_len,
                                   SubnetID subnet_id, bool recreate) {
-    uint128_t capacity;
-    if (lease_type == Lease::TYPE_PD) {
-        auto prefix_len = prefixLengthFromRange(start_address, end_address);
-        capacity = prefixesInRange(prefix_len, delegated_len);
-    } else {
-        capacity = addrsInRange(start_address, end_address);
-    }
+    // This is clunky but it allows us to log the capacity.
+    try {
+        validateV6Range(start_address, end_address);
+        uint128_t capacity;
+        if (lease_type == Lease::TYPE_PD) {
+            auto prefix_len = prefixLengthFromRange(start_address, end_address);
+            capacity = prefixesInRange(prefix_len, delegated_len);
+        } else {
+            capacity = addrsInRange(start_address, end_address);
+        }
 
-    LOG_DEBUG(pgsql_lb_logger, PGSQL_LB_DBG_TRACE_DETAIL, PGSQL_LB_SFLQ_CREATE_POOL6)
-        .arg(start_address.toText())
-        .arg(end_address.toText())
-        .arg(lease_type)
-        .arg(static_cast<uint16_t>(delegated_len))
-        .arg(subnet_id)
-        .arg(recreate)
-        .arg(capacity);
-
-    if (capacity > SharedFlqAllocator::MAX_V6_POOL_SIZE) {
-        isc_throw(BadValue, "PgSqlLeasMgr::sflqCreateFlqPool6 pool capacity "
-                            << capacity << " exceeds limit of "
-                            << SharedFlqAllocator::MAX_V6_POOL_SIZE
-                            << " for shared-flq allocator on V6 pool ");
+        LOG_DEBUG(pgsql_lb_logger, PGSQL_LB_DBG_TRACE_DETAIL, PGSQL_LB_SFLQ_CREATE_POOL6)
+            .arg(start_address.toText())
+            .arg(end_address.toText())
+            .arg(lease_type)
+            .arg(static_cast<uint16_t>(delegated_len))
+            .arg(subnet_id)
+            .arg(recreate)
+            .arg(capacity);
+    } catch (const std::exception& ex) {
+        isc_throw(BadValue, "PgSqlLeasMgr::sflqCreateFlqPool6 " << ex.what());
     }
 
     // Get a context
@@ -4173,6 +4306,8 @@ PgSqlLeaseMgr::sflqPickFreeLease6(IOAddress start_address, IOAddress end_address
         .arg(start_address.toText())
         .arg(end_address.toText());
 
+    validateV6Range(start_address, end_address);
+
     // Get a context
     PgSqlLeaseContextAlloc get_context(*this);
     PgSqlLeaseContextPtr ctx = get_context.ctx_;
@@ -4213,6 +4348,209 @@ PgSqlLeaseMgr::sflqPickFreeLease6(IOAddress start_address, IOAddress end_address
     return (PgSqlExchange::getInetValue6(r, 0, 0));
 }
 
+SflqPoolInfoCollectionPtr
+PgSqlLeaseMgr::sflqPool4GetAll() {
+    LOG_DEBUG(pgsql_lb_logger, PGSQL_LB_DBG_TRACE_DETAIL, PGSQL_LB_SFLQ_POOL4_GET_ALL);
+
+    // No input parameters.
+    PsqlBindArray in_bindings;
+    return (sflqPoolGetCommon(SFLQ_POOL4_GET_ALL, in_bindings));
+}
+
+SflqPoolInfoCollectionPtr
+PgSqlLeaseMgr::sflqPool4Get(SubnetID subnet_id) {
+    LOG_DEBUG(pgsql_lb_logger, PGSQL_LB_DBG_TRACE_DETAIL,
+              PGSQL_LB_SFLQ_POOL4_GET_BY_SUBNET)
+              .arg(subnet_id);
+
+    PsqlBindArray in_bindings;
+    in_bindings.add(subnet_id);
+
+    return (sflqPoolGetCommon(SFLQ_POOL4_GET_BY_SUBNET, in_bindings));
+}
+
+SflqPoolInfoCollectionPtr
+PgSqlLeaseMgr::sflqPool4Get(IOAddress start_address, IOAddress end_address) {
+    LOG_DEBUG(pgsql_lb_logger, PGSQL_LB_DBG_TRACE_DETAIL,
+              PGSQL_LB_SFLQ_POOL4_GET_BY_RANGE)
+              .arg(start_address.toText())
+              .arg(end_address.toText());
+
+    validateV4Range(start_address, end_address);
+
+    PsqlBindArray in_bindings;
+    // Postgresql statement args are numbered so it only needs them once each.
+    in_bindings.add(start_address.toUint32());
+    in_bindings.add(end_address.toUint32());
+
+    return (sflqPoolGetCommon(SFLQ_POOL4_GET_BY_RANGE, in_bindings));
+}
+
+bool
+PgSqlLeaseMgr::sflqPool4Del(IOAddress start_address, IOAddress end_address,
+                            bool force /* = false */) {
+    LOG_DEBUG(pgsql_lb_logger, PGSQL_LB_DBG_TRACE_DETAIL,
+              PGSQL_LB_SFLQ_POOL4_DELETE)
+              .arg(start_address.toText())
+              .arg(end_address.toText())
+              .arg(force ? "true" : "false");
+
+    validateV4Range(start_address, end_address);
+
+    return (sflqPoolDelCommon(start_address, end_address, force, AF_INET));
+}
+
+SflqPoolInfoCollectionPtr
+PgSqlLeaseMgr::sflqPool6GetAll() {
+    LOG_DEBUG(pgsql_lb_logger, PGSQL_LB_DBG_TRACE_DETAIL, PGSQL_LB_SFLQ_POOL6_GET_ALL);
+
+    // No input parameters.
+    PsqlBindArray in_bindings;
+
+    return (sflqPoolGetCommon(SFLQ_POOL6_GET_ALL, in_bindings));
+}
+
+SflqPoolInfoCollectionPtr
+PgSqlLeaseMgr::sflqPool6Get(SubnetID subnet_id) {
+    LOG_DEBUG(pgsql_lb_logger, PGSQL_LB_DBG_TRACE_DETAIL,
+              PGSQL_LB_SFLQ_POOL6_GET_BY_SUBNET)
+              .arg(subnet_id);
+
+    PsqlBindArray in_bindings;
+    in_bindings.add(subnet_id);
+
+    return (sflqPoolGetCommon(SFLQ_POOL6_GET_BY_SUBNET, in_bindings));
+}
+
+SflqPoolInfoCollectionPtr
+PgSqlLeaseMgr::sflqPool6Get(IOAddress start_address, IOAddress end_address) {
+    LOG_DEBUG(pgsql_lb_logger, PGSQL_LB_DBG_TRACE_DETAIL,
+              PGSQL_LB_SFLQ_POOL6_GET_BY_RANGE)
+              .arg(start_address.toText())
+              .arg(end_address.toText());
+
+    validateV6Range(start_address, end_address);
+
+    PsqlBindArray in_bindings;
+    // Postgresql statement args are numbered so it only needs them once each.
+    in_bindings.addInet6(start_address);
+    in_bindings.addInet6(end_address);
+
+    return (sflqPoolGetCommon(SFLQ_POOL6_GET_BY_RANGE, in_bindings));
+}
+
+bool
+PgSqlLeaseMgr::sflqPool6Del(IOAddress start_address, IOAddress end_address,
+                            bool force /* = false */) {
+    LOG_DEBUG(pgsql_lb_logger, PGSQL_LB_DBG_TRACE_DETAIL,
+              PGSQL_LB_SFLQ_POOL6_DELETE)
+              .arg(start_address.toText())
+              .arg(end_address.toText())
+              .arg(force ? "true" : "false");
+
+    validateV6Range(start_address, end_address);
+
+    return (sflqPoolDelCommon(start_address, end_address, force, AF_INET6));
+}
+
+SflqPoolInfoCollectionPtr
+PgSqlLeaseMgr::sflqPoolGetCommon(const StatementIndex& stindex,
+                                 const PsqlBindArray& where_bindings) {
+    // Get a context
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
+    SflqPoolInfoCollectionPtr pools(new SflqPoolInfoCollection());
+
+    ctx->conn_.selectQuery(tagged_statements[stindex], where_bindings,
+                           [this, &pools]
+                           (PgSqlResult& r, int row) {
+        // Create a convenience worker for the row.
+        PgSqlResultRowWorker worker(r, row);
+        SflqPoolInfoPtr info(new SflqPoolInfo());
+
+        // db pool id is 0, we skip it
+
+        info->subnet_id_ = worker.getInt(1);
+
+        auto lease_type_ = worker.getInt(2);
+        switch(lease_type_) {
+        case Lease::TYPE_V4:
+            info->lease_type_ = Lease::TYPE_V4;
+            break;
+        case Lease::TYPE_NA:
+            info->lease_type_ = Lease::TYPE_NA;
+            break;
+        case Lease::TYPE_PD:
+            info->lease_type_ = Lease::TYPE_PD;
+            break;
+        default:
+            isc_throw(BadValue, "invalid pool lease type returned " <<
+                      static_cast<int>(lease_type_));
+        }
+
+        if (lease_type_ == Lease::TYPE_V4) {
+            info->start_address_ = IOAddress(worker.getInt(3));
+            info->end_address_ = IOAddress(worker.getInt(4));
+        } else {
+            info->start_address_ = worker.getInet6(3);
+            info->end_address_ = worker.getInet6(4);
+        }
+
+        info->delegated_len_ = worker.getInt(5);
+        info->created_ts_ = worker.getTimestamp(6);
+        info->modified_ts_ = worker.getTimestamp(7);
+        info->free_leases_ = worker.getInt(8);
+        pools->push_back(info);
+    });
+
+    return (pools);
+}
+
+bool
+PgSqlLeaseMgr::sflqPoolDelCommon(IOAddress start_address, IOAddress end_address,
+                                 bool force, uint16_t family ) {
+    // If force is false check for overlapping pools.
+    if (!force) {
+        auto pools_in_range = (family == AF_INET ? sflqPool4Get(start_address, end_address)
+                                                 : sflqPool6Get(start_address, end_address));
+        auto count = pools_in_range->size();
+        if (count == 0) {
+            // Nothing to do.
+            return (false);
+        }
+
+        if (count > 1) {
+            // Overlapping pools, warn and bail.
+            isc_throw(InvalidOperation, "Delete would affect "
+                      << count << " overlapping pools");
+        }
+    }
+
+    // Get a context.
+    PgSqlLeaseContextAlloc get_context(*this);
+    PgSqlLeaseContextPtr ctx = get_context.ctx_;
+
+    // Make where clause bindings.
+    PsqlBindArray in_bindings;
+    StatementIndex stindex;
+    if (family == AF_INET) {
+        in_bindings.add(start_address.toUint32());
+        in_bindings.add(end_address.toUint32());
+        stindex = SFLQ_POOL4_DELETE;
+    } else {
+        in_bindings.addInet6(start_address);
+        in_bindings.addInet6(end_address);
+        stindex = SFLQ_POOL6_DELETE;
+    }
+
+    ScopedPgSqlTransactionPtr trans(new PgSqlTransaction(ctx->conn_));
+    auto affected_rows = ctx->conn_.updateDeleteQuery(tagged_statements[stindex], in_bindings);
+    trans->commit();
+
+    return(affected_rows > 0);
+}
+
 TrackingLeaseMgrPtr
 PgSqlLeaseMgr::factory(const isc::db::DatabaseConnection::ParameterMap& parameters) {
     LOG_INFO(pgsql_lb_logger, PGSQL_LB_DB)
index 5ab95f95f45152dfd777ac349d5a4562fea5bdd9..8d9e292d2a1ad18dc63f33000b9d206846ef6928 100644 (file)
@@ -828,6 +828,14 @@ public:
         SFLQ_INSERT_LEASE6,          // SFLQ Alternate for inserting v6 lease
         SFLQ_UPDATE_LEASE6,          // SFLQ Alternate for updating v6 lease
         SFLQ_DELETE_LEASE6,          // SFLQ Alternate for deleting v6 lease
+        SFLQ_POOL4_GET_ALL,          // SFLQ Fetch all v4 shared flq pools
+        SFLQ_POOL4_GET_BY_SUBNET,    // SFLQ Fetch all v4 shared flq pools for a subnet
+        SFLQ_POOL4_GET_BY_RANGE,     // SFLQ Fetch v4 shared flq pools that overlap the given range
+        SFLQ_POOL4_DELETE,           // SFLQ Delete v4 shared flq pool for an address range
+        SFLQ_POOL6_GET_ALL,          // SFLQ Fetch all v6 shared flq pools
+        SFLQ_POOL6_GET_BY_SUBNET,    // SFLQ Fetch all v6 shared flq pools for a subnet
+        SFLQ_POOL6_GET_BY_RANGE,     // SFLQ Fetch v4 shared flq pool that overlap the address range
+        SFLQ_POOL6_DELETE,           // SFLQ Delete v4 shared flq pool for an address range
         NUM_STATEMENTS               // Number of statements
     };
 
@@ -1286,6 +1294,122 @@ public:
     /// @return A free V6 address/prefix or IOAddress::IPV6_ZERO_ADDRESS().
     virtual asiolink::IOAddress sflqPickFreeLease6(asiolink::IOAddress start_address,
                                                    asiolink::IOAddress end_address) override;
+
+    /// @brief Fetch all SFLQ V4 pools.
+    ///
+    /// @return A collection of the SFLQ V4 pools.
+    virtual SflqPoolInfoCollectionPtr sflqPool4GetAll() override;
+
+    /// @brief Fetch all SFLQ V4 pools belonging to a subnet.
+    ///
+    /// @param subnet_id id of the desired subnet.
+    ///
+    /// @return A collection of the SFLQ V4 pools.
+    virtual SflqPoolInfoCollectionPtr sflqPool4Get(SubnetID subnet_id) override;
+
+    /// @brief Fetch all SFLQ V4 pools that overlap an address range.
+    ///
+    /// Since overlapping pools are supported, this function returns all V4
+    /// SFLQ pools whose range overlaps the given range.
+    ///
+    /// @param start_address range start address
+    /// @param end_address range end address
+    ///
+    /// @return A collection of the SFLQ V4 pools.
+    virtual SflqPoolInfoCollectionPtr sflqPool4Get(asiolink::IOAddress start_address,
+                                                   asiolink::IOAddress end_address)
+                                                   override;
+    /// @brief Delete the SFLQ V4 pool that matches a start and end address.
+    ///
+    /// Deletes the flq_pool4 entry along with its free_lease4 data.
+    /// Fails If there are multiple pools that overalap the given range
+    /// unless force is true.
+    ///
+    /// @param start_address start address of the pool to delete.
+    /// @param end_address end address of the pool to delete.
+    /// @param force overrides check for overlapping pools when true. Defaults
+    /// to false.
+    ///
+    /// @return True a pool was deleted.
+    /// @throw InvalidOperation if force is false and overlapping pools are
+    /// detected.
+    virtual bool sflqPool4Del(asiolink::IOAddress start_address,
+                              asiolink::IOAddress end_address,
+                              bool force = false) override;
+
+    /// @brief Fetch all SFLQ V6 pools.
+    ///
+    /// @return A collection of the SFLQ V6 pools.
+    virtual SflqPoolInfoCollectionPtr sflqPool6GetAll() override;
+
+    /// @brief Fetch all SFLQ V6 pools belonging to a subnet.
+    ///
+    /// @param subnet_id id of the desired subnet.
+    ///
+    /// @return A collection of the SFLQ V6 pools.
+    virtual SflqPoolInfoCollectionPtr sflqPool6Get(SubnetID subnet_id) override;
+
+    /// @brief Fetch all SFLQ V6 pools that overlap an address range.
+    ///
+    /// Since overlapping pools are supported, this function returns all V4
+    /// SFLQ pools whose range overlaps the given range.
+    ///
+    /// @param start_address range start address
+    /// @param end_address range end address
+    ///
+    /// @return A collection of the SFLQ V6 pools.
+    virtual SflqPoolInfoCollectionPtr sflqPool6Get(asiolink::IOAddress start_address,
+                                                   asiolink::IOAddress end_address)
+                                                   override;
+    /// @brief Delete the SFLQ V6 pool that matches a start and end address.
+    ///
+    /// Deletes the flq_pool6 entry along with its free_lease6 data.
+    /// Fails If there are multiple pools that overalap the given range
+    /// unless force is true.
+    ///
+    /// @param start_address start address of the pool to delete.
+    /// @param end_address end address of the pool to delete.
+    /// @param force overrides check for overlapping pools when true. Defaults
+    /// to false.
+    ///
+    /// @return True a pool was deleted.
+    /// @throw InvalidOperation if force is false and overlapping pools are
+    /// detected.
+    virtual bool sflqPool6Del(asiolink::IOAddress start_address,
+                              asiolink::IOAddress end_address,
+                              bool force = false) override;
+
+private:
+    /// @brief Fetch SFLQ pools based on statement index and option where clause.
+    ///
+    /// Common function used for all variants. Requires that all selects return
+    /// values for all the columns and in the same order.
+    ///
+    /// @param stindex index of the SQL statement to execute.
+    /// @param where_bindings input bindings holding the where clause parameter
+    /// values (if any)
+    /// @param family protocl family AF_INET or AF_INET6
+    ///
+    /// @return A collection of the SFLQ V4 pools.
+    SflqPoolInfoCollectionPtr sflqPoolGetCommon(const StatementIndex& stindex,
+                                                const db::PsqlBindArray& where_bindings);
+    /// @brief Delete the SFLQ pool that matches a start and end address.
+    ///
+    /// Deletes the flq_poolX entry along with its free_leaseX data.
+    /// Fails If there are multiple pools that overalap the given range
+    /// unless force is true.
+    ///
+    /// @param start_address start address of the pool to delete.
+    /// @param end_address end address of the pool to delete.
+    /// @param force overrides check for overlapping pools when true.
+    /// @param family protocl family AF_INET or AF_INET6
+    ///
+    /// @return True a pool was deleted.
+    /// @throw InvalidOperation if force is false and overlapping pools are
+    /// detected.
+    bool sflqPoolDelCommon(asiolink::IOAddress start_address, asiolink::IOAddress end_address,
+                           bool force, uint16_t family);
+
     /// @brief Write V4 leases to a file.
     virtual void writeLeases4(const std::string& /*filename*/) override;