]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
sqlippools: allocate_requested queries for MySQL
authorTerry Burton <tez@terryburton.co.uk>
Tue, 8 Sep 2020 18:06:30 +0000 (19:06 +0100)
committerAlan DeKok <aland@freeradius.org>
Thu, 10 Sep 2020 12:56:41 +0000 (08:56 -0400)
raddb/mods-config/sql/ippool-dhcp/mysql/procedure-no-skip-locked.sql
raddb/mods-config/sql/ippool-dhcp/mysql/procedure.sql
raddb/mods-config/sql/ippool-dhcp/mysql/queries.conf

index 229df13b5e5511ba7aa30c6663399a76ab3630f8..8d919c711aceea5da31759aaaa7b9c1f1d35ae59 100644 (file)
@@ -33,7 +33,8 @@
 --             '%{control:${pool_name}}', \
 --             '%{DHCP-Gateway-IP-Address}', \
 --             '${pool_key}', \
---             ${lease_duration} \
+--             ${lease_duration}, \
+--             '%{%{${req_attribute_name}}:-0.0.0.0}' \
 --     )"
 -- allocate_update = ""
 -- allocate_commit = ""
@@ -46,13 +47,23 @@ CREATE PROCEDURE fr_allocate_previous_or_new_framedipaddress (
        IN v_pool_name VARCHAR(64),
        IN v_gateway VARCHAR(15),
        IN v_pool_key VARCHAR(64),
-       IN v_lease_duration INT
+       IN v_lease_duration INT,
+       IN v_requested_address VARCHAR(15)
 )
 proc:BEGIN
        DECLARE r_address VARCHAR(15);
 
        -- Reissue an existing IP address lease when re-authenticating a session
        --
+       -- Note: In this query we get away without the need for FOR UPDATE
+       --       becase:
+       --
+       --         (a) Each existing lease only belongs to a single device, so
+       --             no two devices will be racing over a single address.
+       --         (b) The set of existing leases (not yet expired) are
+       --             disjoint from the set of free leases, so not subject to
+       --             reallocation.
+       --
        SELECT framedipaddress INTO r_address
        FROM dhcpippool
        WHERE pool_name = v_pool_name
@@ -75,6 +86,15 @@ proc:BEGIN
        --      AND `status` IN ('dynamic', 'static')
        -- LIMIT 1;
 
+       --
+       -- Normally here we would honour an IP address hint if the IP were
+       -- available, however we cannot do that without taking a lock which
+       -- defeats the purpose of this version of the stored procedure.
+       --
+       -- It you need to honour an IP address hint then use a database with
+       -- support for SKIP LOCKED and use the normal stored procedure.
+       --
+
        IF r_address IS NOT NULL THEN
                UPDATE dhcpippool
                SET
index e9eb7d4911b6a065a6b85fbabad55de084224c87..d3f9dd5d2c45f09d94cf04a123af6b63ebb893ed 100644 (file)
@@ -21,7 +21,8 @@
 --             '%{control:${pool_name}}', \
 --             '%{DHCP-Gateway-IP-Address}', \
 --             '${pool_key}', \
---             ${lease_duration} \
+--             ${lease_duration}, \
+--             '%{%{${req_attribute_name}}:-0.0.0.0}' \
 --     )"
 -- allocate_update = ""
 -- allocate_commit = ""
@@ -34,7 +35,8 @@ CREATE PROCEDURE fr_dhcp_allocate_previous_or_new_framedipaddress (
        IN v_pool_name VARCHAR(30),
        IN v_gateway VARCHAR(15),
        IN v_pool_key VARCHAR(30),
-       IN v_lease_duration INT
+       IN v_lease_duration INT,
+       IN v_requested_address VARCHAR(15)
 )
 proc:BEGIN
        DECLARE r_address VARCHAR(15);
@@ -79,6 +81,19 @@ proc:BEGIN
        -- FOR UPDATE;
        -- -- FOR UPDATE SKIP LOCKED;  -- Better performance, but limited support
 
+       -- Issue the requested IP address if it is available
+       --
+       IF r_address IS NULL AND v_requested_address <> '0.0.0.0' THEN
+               SELECT framedipaddress INTO r_address
+               FROM dhcpippool
+               WHERE pool_name = v_pool_name
+                       AND framedipaddress = v_requested_address
+                       AND `status` = 'dynamic'
+                       AND ( pool_key = v_pool_key OR expiry_time < NOW() )
+               FOR UPDATE;
+--           FOR UPDATE SKIP LOCKED;  -- Better performance, but limited support
+       END IF;
+
        -- If we didn't reallocate a previous address then pick the least
        -- recently used address from the pool which maximises the likelihood
        -- of re-assigning the other addresses to their recent user
index 95db82cd040d5b4fdc8169f3bd64581375c1ec80..c9b9147298413315f051f1d78d70828a33ca4961 100644 (file)
@@ -22,6 +22,17 @@ allocate_existing = "\
        AND `status` IN ('dynamic', 'static') \
        ORDER BY expiry_time DESC LIMIT 1 FOR UPDATE SKIP LOCKED"
 
+#
+#  Determine whether the requested IP address is available
+#
+allocate_requested = "\
+       SELECT framedipaddress FROM ${ippool_table} \
+       WHERE pool_name = '%{control:${pool_name}}' \
+       AND framedipaddress = '%{%{${req_attribute_name}}:-0.0.0.0}' \
+       AND `status` = 'dynamic' \
+       AND ( pool_key = '${pool_key}' OR expiry_time < NOW() ) \
+       FOR UPDATE SKIP LOCKED"
+
 #
 #  If the existing address can't be found this query will be run to
 #  find a free address
@@ -40,22 +51,29 @@ allocate_find = "\
 #
 
 #
-#  Alternatively do both operations in one query.  Depending on transaction
+#  Alternatively do the operations in one query.  Depending on transaction
 #  isolation mode, this can cause deadlocks
 #
 #allocate_find = "\
-#      (SELECT framedipaddress, pool_key, expiry_time FROM ${ippool_table} \
+#      (SELECT framedipaddress, 1 AS o FROM ${ippool_table} \
 #              WHERE pool_name = '%{control:${pool_name}}' \
 #              AND pool_key = '${pool_key}' \
 #              AND `status` IN ('dynamic', 'static') \
 #              ORDER BY expiry_time DESC LIMIT 1 FOR UPDATE SKIP LOCKED \
 #      ) UNION ( \
-#      SELECT framedipaddress, pool_key, expiry_time FROM ${ippool_table} \
+#      SELECT framedipaddress, 2 AS o FROM ${ippool_table} \
+#              WHERE pool_name = '%{control:${pool_name}}' \
+#              AND framedipaddress = '%{%{${req_attribute_name}}:-0.0.0.0}' \
+#              AND `status` = 'dynamic' \
+#              AND ( pool_key = '${pool_key}' OR expiry_time < NOW() ) \
+#              FOR UPDATE SKIP LOCKED \
+#      ) UNION ( \
+#      SELECT framedipaddress, 3 AS o FROM ${ippool_table} \
 #              WHERE pool_name = '%{control:${pool_name}}' \
 #              AND expiry_time < NOW() \
 #              AND `status` = 'dynamic' \
 #              ORDER BY expiry_time LIMIT 1 FOR UPDATE SKIP LOCKED \
-#      ) ORDER BY (pool_key <> '${pool_key}'), expiry_time \
+#      ) ORDER BY o \
 #      LIMIT 1"
 
 #
@@ -118,7 +136,8 @@ allocate_update = "\
 #              '%{control:${pool_name}}', \
 #              '%{DHCP-Gateway-IP-Address}', \
 #              '${pool_key}', \
-#              ${offer_duration} \
+#              ${offer_duration}, \
+#              '%{%{${req_attribute_name}}:-0.0.0.0}' \
 #      )"
 #allocate_update = ""
 #allocate_commit = ""