-- '%{control:${pool_name}}', \
-- '%{DHCP-Gateway-IP-Address}', \
-- '${pool_key}', \
--- ${lease_duration} \
+-- ${lease_duration}, \
+-- '%{%{${req_attribute_name}}:-0.0.0.0}' \
-- )"
-- allocate_update = ""
-- allocate_commit = ""
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
-- 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
-- '%{control:${pool_name}}', \
-- '%{DHCP-Gateway-IP-Address}', \
-- '${pool_key}', \
--- ${lease_duration} \
+-- ${lease_duration}, \
+-- '%{%{${req_attribute_name}}:-0.0.0.0}' \
-- )"
-- allocate_update = ""
-- allocate_commit = ""
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);
-- 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
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
#
#
-# 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"
#
# '%{control:${pool_name}}', \
# '%{DHCP-Gateway-IP-Address}', \
# '${pool_key}', \
-# ${offer_duration} \
+# ${offer_duration}, \
+# '%{%{${req_attribute_name}}:-0.0.0.0}' \
# )"
#allocate_update = ""
#allocate_commit = ""