41RCSID(
"$Id: 28dbbe241c104e650ab2b8b19be42a6522cfa437 $")
43#include <freeradius-devel/server/base.h>
44#include <freeradius-devel/server/module_rlm.h>
45#include <freeradius-devel/server/modpriv.h>
47#include <freeradius-devel/util/debug.h>
48#include <freeradius-devel/util/base16.h>
49#include <freeradius-devel/util/token.h>
51#include <freeradius-devel/redis/base.h>
52#include <freeradius-devel/redis/cluster.h>
207 .pair.dflt =
"reply.IP-Pool.Range", .pair.dflt_quote =
T_BARE_WORD },
226 .pair.dflt =
"reply.IP-Pool.Range", .pair.dflt_quote =
T_BARE_WORD },
277 "local address_key" EOL
278 "local owner_key" EOL
283 "local wall_time = tonumber(ARGV[1])" EOL
292 "exists = redis.call('GET', owner_key);" EOL
294 " local expires = tonumber(redis.call('ZSCORE', pool_key, exists))" EOL
297 " ip = redis.call('HMGET', '{' .. KEYS[1] .. '}:"IPPOOL_ADDRESS_KEY":' .. exists, 'device', 'range', 'counter', 'gateway')" EOL
298 " if ip and (ip[1] == ARGV[3]) then" EOL
299 " if expires_in < tonumber(ARGV[2]) then" EOL
301 " expires_in = tonumber(ARGV[2])" EOL
302 " if not static then" EOL
303 " redis.call('EXPIRE', owner_key, ARGV[4])" EOL
310 " if ARGV[5] ~= ip[5] then" EOL
321 "if ARGV[6] and ARGV[6] ~= '' then" EOL
322 " local expires = tonumber(redis.call('ZSCORE', pool_key, ARGV[6]))" EOL
323 " if expires and tonumber(expires) < wall_time then" EOL
324 " ip = { ARGV[6] }" EOL
332 " ip = redis.call('ZREVRANGE', pool_key, -1, -1, 'WITHSCORES')" EOL
333 " if not ip or not ip[1] then" EOL
336 " if tonumber(ip[2]) >= wall_time then" EOL
340 "redis.call('ZADD', pool_key, 'XX', ARGV[1] + ARGV[2], ip[1])" EOL
346 "redis.call('HMSET', address_key, 'device', ARGV[3], 'gateway', ARGV[5])" EOL
347 "redis.call('SET', owner_key, ip[1])" EOL
348 "redis.call('EXPIRE', owner_key, ARGV[4])" EOL
352 " redis.call('HGET', address_key, 'range'), " EOL
353 " tonumber(ARGV[2]), " EOL
354 " redis.call('HINCRBY', address_key, 'counter', 1)" EOL
379 "local address_key" EOL
380 "local owner_key" EOL
387 "found = redis.call('HMGET', address_key, 'range', 'device', 'gateway', 'counter' )" EOL
391 "if not found[2] then" EOL
394 "if found[2] ~= ARGV[4] then" EOL
402 "local expires = tonumber(redis.call('ZSCORE', pool_key, ARGV[3]))" EOL
413 "if not static and (redis.call('EXPIRE', owner_key, ARGV[2]) == 0) then" EOL
414 " redis.call('SET', owner_key, ARGV[3])" EOL
415 " redis.call('EXPIRE', owner_key, ARGV[5])" EOL
421 "if ARGV[6] ~= found[3] then" EOL
422 " redis.call('HSET', address_key, 'gateway', ARGV[6])" EOL
448 "local address_key" EOL
449 "local owner_key" EOL
456 "found = redis.call('HGET', address_key, 'device')" EOL
457 "if not found then" EOL
460 "if found and found ~= ARGV[3] then" EOL
468 "found = tonumber(redis.call('ZSCORE', pool_key, ARGV[2]))" EOL
477 "if not static then" EOL
479 " if tonumber(ARGV[4]) > 0 then" EOL
480 " redis.call('EXPIRE', owner_key, ARGV[4])" EOL
482 " redis.call('DEL', owner_key)" EOL
487 " redis.call('HINCRBY', address_key, 'counter', 1) - 1" EOL
502 if (!wait_num)
return 0;
504 if (reply->type != REDIS_REPLY_INTEGER) {
505 REDEBUG(
"WAIT result is wrong type, expected integer got %s",
509 if (reply->integer < wait_num) {
510 REDEBUG(
"Too few slaves acknowledged allocation, needed %i, got %lli",
511 wait_num, reply->integer);
525 char *device_str = NULL, *gateway_str = NULL;
527 if (gateway_id && gateway_id->vb_length > 0) gateway_str =
fr_asprint(request, gateway_id->vb_strvalue,
528 gateway_id->vb_length,
'"');
529 if (owner && owner->vb_length > 0) device_str =
fr_asprint(request, owner->vb_strvalue, owner->vb_length,
'"');
533 RDEBUGX(lvl,
"Allocating lease from pool \"%pV\"%s%s%s%s%s%s, expires in %us",
535 device_str ?
", to \"" :
"", device_str ? device_str :
"",
536 device_str ?
"\"" :
"",
537 gateway_str ?
", on \"" :
"", gateway_str ? gateway_str :
"",
538 gateway_str ?
"\"" :
"",
543 RDEBUGX(lvl,
"Updating %pV in pool \"%pV\"%s%s%s%s%s%s, expires in %us",
545 device_str ?
", device \"" :
"", device_str ? device_str :
"",
546 device_str ?
"\"" :
"",
547 gateway_str ?
", gateway \"" :
"", gateway_str ? gateway_str :
"",
548 gateway_str ?
"\"" :
"",
553 RDEBUGX(lvl,
"Releasing %pV%s%s%s to pool \"%pV\"",
555 device_str ?
" leased by \"" :
"", device_str ? device_str :
"",
556 device_str ?
"\"" :
"",
593 uint8_t const *key,
size_t key_len,
595 char const digest[],
char const *script,
596 char const *cmd, ...)
599 redisReply *replies[5];
600 size_t reply_cnt = 0, i;
604 unsigned int pipelined = 0;
611 memset(replies, 0,
sizeof(replies));
621 RDEBUG3(
"Calling script 0x%s", digest);
623 redisvAppendCommand(conn->
handle, cmd, copy);
645 RDEBUG3(
"Loading script 0x%s", digest);
646 redisAppendCommand(conn->
handle,
"MULTI");
647 redisAppendCommand(conn->
handle,
"SCRIPT LOAD %s", script);
649 redisvAppendCommand(conn->
handle, cmd, copy);
651 redisAppendCommand(conn->
handle,
"EXEC");
666 if (replies[3]->
type != REDIS_REPLY_ARRAY) {
667 RERROR(
"Bad response to EXEC, expected array got %s",
674 if (replies[3]->elements != 2) {
675 RERROR(
"Bad response to EXEC, expected 2 result elements, got %zu",
676 replies[3]->elements);
679 if (replies[3]->element[0]->
type != REDIS_REPLY_STRING) {
680 RERROR(
"Bad response to SCRIPT LOAD, expected string got %s",
684 if (strcmp(replies[3]->element[0]->str, digest) != 0) {
685 RWDEBUG(
"Incorrect SHA1 from SCRIPT LOAD, expected %s, got %s",
686 digest, replies[3]->element[0]->str);
712 *
out = replies[3]->element[1];
713 replies[3]->element[1] = NULL;
733 redisReply *reply = NULL;
752 "EVALSHA %s 1 %b %u %u %b %u %b %u",
755 (
unsigned int)now.tv_sec, lease_time,
772 "EVALSHA %s 1 %b %u %u %b %u %b %s",
775 (
unsigned int)now.tv_sec, lease_time,
787 if (reply->type != REDIS_REPLY_ARRAY) {
788 REDEBUG(
"Expected result to be array got \"%s\"",
794 if (reply->elements == 0) {
795 REDEBUG(
"Got empty result array");
803 if (reply->element[0]->type != REDIS_REPLY_INTEGER) {
804 REDEBUG(
"Server returned unexpected type \"%s\" for rcode element (result[0])",
809 ret = reply->element[0]->integer;
810 if (ret < 0)
goto finish;
815 if (reply->elements > 1) {
824 switch (reply->element[1]->type) {
831 case REDIS_REPLY_INTEGER:
839 RPEDEBUG(
"Failed converting integer to IPv4 address");
850 case REDIS_REPLY_STRING:
852 NULL, reply->element[1]->str, reply->element[1]->len,
false);
861 REDEBUG(
"Server returned unexpected type \"%s\" for IP element (result[1])",
871 if (reply->elements > 2) {
872 switch (reply->element[2]->type) {
876 case REDIS_REPLY_STRING:
887 NULL, reply->element[2]->str, reply->element[2]->len,
true);
895 case REDIS_REPLY_NIL:
899 REDEBUG(
"Server returned unexpected type \"%s\" for range element (result[2])",
918 if (reply->element[3]->type != REDIS_REPLY_INTEGER) {
919 REDEBUG(
"Server returned unexpected type \"%s\" for expiry element (result[3])",
947 redisReply *reply = NULL;
958 if ((ip->
af == AF_INET) &&
inst->ipv4_integer) {
963 "EVALSHA %s 1 %b %u %u %u %b %u %b",
966 (
unsigned int)now.tv_sec, expires,
967 htonl(ip->
addr.v4.s_addr),
968 (
uint8_t const *)owner->vb_strvalue, owner->vb_length,
970 (
uint8_t const *)gateway_id->vb_strvalue, gateway_id->vb_length);
979 "EVALSHA %s 1 %b %u %u %s %b %u %b",
982 (
unsigned int)now.tv_sec, expires,
984 (
uint8_t const *)owner->vb_strvalue, owner->vb_length,
986 (
uint8_t const *)gateway_id->vb_strvalue, gateway_id->vb_length);
993 if (reply->type != REDIS_REPLY_ARRAY) {
994 REDEBUG(
"Expected result to be array got \"%s\"",
1000 if (reply->elements == 0) {
1001 REDEBUG(
"Got empty result array");
1009 if (reply->element[0]->type != REDIS_REPLY_INTEGER) {
1010 REDEBUG(
"Server returned unexpected type \"%s\" for rcode element (result[0])",
1015 ret = reply->element[0]->integer;
1016 if (ret < 0)
goto finish;
1021 if (reply->elements > 1) {
1022 switch (reply->element[1]->type) {
1026 case REDIS_REPLY_STRING:
1033 reply->element[1]->str, reply->element[1]->len,
true);
1041 case REDIS_REPLY_NIL:
1045 REDEBUG(
"Server returned unexpected type \"%s\" for range element (result[1])",
1057 map_t expiry_map = {
1088 redisReply *reply = NULL;
1095 if ((ip->
af == AF_INET) &&
inst->ipv4_integer) {
1097 (
uint8_t const *)key_prefix->vb_strvalue, key_prefix->vb_length,
1098 inst->wait_num,
inst->wait_timeout,
1100 "EVALSHA %s 1 %b %u %u %b %u",
1102 (
uint8_t const *)key_prefix->vb_strvalue, key_prefix->vb_length,
1103 (
unsigned int)now.tv_sec,
1104 htonl(ip->
addr.v4.s_addr),
1105 (
uint8_t const *)owner->vb_strvalue, owner->vb_length, assoc_time);
1111 (
uint8_t const *)key_prefix->vb_strvalue, key_prefix->vb_length,
1112 inst->wait_num,
inst->wait_timeout,
1114 "EVALSHA %s 1 %b %u %s %b %u",
1116 (
uint8_t const *)key_prefix->vb_strvalue, key_prefix->vb_length,
1117 (
unsigned int)now.tv_sec,
1119 (
uint8_t const *)owner->vb_strvalue, owner->vb_length, assoc_time);
1126 if (reply->type != REDIS_REPLY_ARRAY) {
1127 REDEBUG(
"Expected result to be array got \"%s\"",
1133 if (reply->elements == 0) {
1134 REDEBUG(
"Got empty result array");
1142 if (reply->element[0]->type != REDIS_REPLY_INTEGER) {
1143 REDEBUG(
"Server returned unexpected type \"%s\" for rcode element (result[0])",
1148 ret = reply->element[0]->integer;
1149 if (ret < 0)
goto finish;
1157#define CHECK_POOL_NAME \
1158 if (env->pool_name.vb_length > IPPOOL_MAX_KEY_PREFIX_SIZE) { \
1159 REDEBUG("Pool name too long. Expected %u bytes, got %ld bytes", \
1160 IPPOOL_MAX_KEY_PREFIX_SIZE, env->pool_name.vb_length); \
1161 RETURN_UNLANG_FAIL; \
1163 if (env->pool_name.vb_length == 0) { \
1164 RDEBUG2("Empty pool name. Doing nothing"); \
1165 RETURN_UNLANG_NOOP; \
1186 RDEBUG2(
"IP address lease allocated");
1190 RWDEBUG(
"Pool contains no free addresses");
1217 if (
inst->copy_on_update) {
1230 RPEDEBUG(
"Failed copying IP address to reply attribute");
1244 REDEBUG(
"Requested IP address \"%pV\" is not a member of the specified pool",
1249 REDEBUG(
"Requested IP address' \"%pV\" lease already expired at time of renewal",
1254 REDEBUG(
"Requested IP address' \"%pV\" lease allocated to another device",
1284 REDEBUG(
"Requested IP address \"%pV\" is not a member of the specified pool",
1289 REDEBUG(
"Requested IP address' \"%pV\" lease allocated to another device",
1301 RDEBUG2(
"Bulk release not yet implemented");
1307 static bool done_hash =
false;
1315 if (!
inst->cluster)
return -1;
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
#define fr_base16_encode(_out, _in)
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
#define CALL_ENV_TERMINATOR
#define FR_CALL_ENV_METHOD_OUT(_inst)
Helper macro for populating the size/type fields of a call_env_method_t from the output structure typ...
call_env_parser_t const * env
Parsing rules for call method env.
@ CALL_ENV_FLAG_CONCAT
If the tmpl produced multiple boxes they should be concatenated.
@ CALL_ENV_FLAG_ATTRIBUTE
Tmpl MUST contain an attribute reference.
@ CALL_ENV_FLAG_REQUIRED
Associated conf pair or section is required.
@ CALL_ENV_FLAG_BARE_WORD_ATTRIBUTE
bare words are treated as an attribute, but strings may be xlats.
@ CALL_ENV_FLAG_NULLABLE
Tmpl expansions are allowed to produce no output.
#define FR_CALL_ENV_OFFSET(_name, _cast_type, _flags, _struct, _field)
Specify a call_env_parser_t which writes out runtime results to the specified field.
#define FR_CALL_ENV_PARSE_ONLY_OFFSET(_name, _cast_type, _flags, _struct, _parse_field)
Specify a call_env_parser_t which writes out the result of the parsing phase to the field specified.
#define CONF_PARSER_TERMINATOR
#define FR_CONF_DEPRECATED(_name, _struct, _field)
conf_parser_t entry which raises an error if a matching CONF_PAIR is found
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
fr_token_t quote
Quoting around the default value. Only used for templates.
#define FR_CONF_POINTER(_name, _type, _flags, _res_p)
conf_parser_t which parses a single CONF_PAIR producing a single global result
@ CONF_FLAG_SUBSECTION
Instead of putting the information into a configuration structure, the configuration file routines MA...
Defines a CONF_PAIR to C data type mapping.
A section grouping multiple CONF_PAIR.
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
fr_redis_rcode_t fr_redis_cluster_state_next(fr_redis_cluster_state_t *state, fr_redis_conn_t **conn, fr_redis_cluster_t *cluster, request_t *request, fr_redis_rcode_t status, redisReply **reply)
Get the next connection to attempt a command against.
fr_redis_cluster_t * fr_redis_cluster_alloc(TALLOC_CTX *ctx, CONF_SECTION *module, fr_redis_conf_t *conf, char const *log_prefix, char const *trigger_prefix, fr_pair_list_t *trigger_args)
Allocate and initialise a new cluster structure.
fr_redis_rcode_t fr_redis_cluster_state_init(fr_redis_cluster_state_t *state, fr_redis_conn_t **conn, fr_redis_cluster_t *cluster, request_t *request, uint8_t const *key, size_t key_len, bool read_only)
Resolve a key to a pool, and reserve a connection in that pool.
bool fr_redis_cluster_min_version(fr_redis_cluster_t *cluster, char const *min_version)
Check if members of the cluster are above a certain version.
Redis connection sequence state.
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
union fr_ipaddr_t::@137 addr
#define FR_IPADDR_PREFIX_STRLEN
Like FR_IPADDR_STRLEN but with space for a prefix.
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
#define RDEBUGX(_l, fmt,...)
#define RPEDEBUG(fmt,...)
int map_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, map_t const *map, UNUSED void *uctx)
Convert a map to a fr_pair_t.
int map_to_request(request_t *request, map_t const *map, radius_map_getvalue_t func, void *ctx)
Convert map_t to fr_pair_t (s) and add them to a request_t.
@ L_DBG_LVL_3
3rd highest priority debug messages (-xxx | -Xx).
@ L_DBG_LVL_2
2nd highest priority debug messages (-xx | -X).
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
void * env_data
Per call environment data.
module_instance_t const * mi
Instance of the module being instantiated.
module_instance_t * mi
Instance of the module being instantiated.
Temporary structure to hold arguments for module calls.
Temporary structure to hold arguments for instantiation calls.
module_t common
Common fields presented by all modules.
char * fr_asprint(TALLOC_CTX *ctx, char const *in, ssize_t inlen, char quote)
Escape string that may contain binary data, and write it to a new buffer.
static const conf_parser_t config[]
#define RETURN_UNLANG_UPDATED
#define RETURN_UNLANG_INVALID
#define RETURN_UNLANG_NOTFOUND
#define RETURN_UNLANG_FAIL
#define RETURN_UNLANG_NOOP
void fr_redis_reply_print(fr_log_lvl_t lvl, redisReply *reply, request_t *request, int idx, fr_redis_rcode_t status)
Print the response data in a useful treelike form.
static void fr_redis_pipeline_free(redisReply *reply[], size_t num)
redisContext * handle
Hiredis context used when issuing commands.
#define REDIS_COMMON_CONFIG
static void fr_redis_reply_free(redisReply **reply)
Wrap freeReplyObject so we consistently check for NULL pointers.
void fr_redis_version_print(void)
Print the version of libhiredis the server was built against.
fr_table_num_sorted_t const redis_reply_types[]
fr_redis_rcode_t fr_redis_pipeline_result(unsigned int *pipelined, fr_redis_rcode_t *rcode, redisReply *out[], size_t out_len, fr_redis_conn_t *conn)
Simplifies handling of pipelined commands with Redis cluster.
fr_redis_rcode_t
Codes are ordered inversely by priority.
@ REDIS_RCODE_SUCCESS
Operation was successful.
@ REDIS_RCODE_TRY_AGAIN
Try the operation again.
@ REDIS_RCODE_NO_SCRIPT
Script doesn't exist.
@ REDIS_RCODE_ERROR
Unrecoverable library/server error.
Configuration parameters for a redis connection.
Connection handle, holding a redis context.
#define IPPOOL_STATIC_BIT
#define _IPPOOL_RCODE_NOT_FOUND
#define _IPPOOL_RCODE_POOL_EMPTY
@ IPPOOL_RCODE_DEVICE_MISMATCH
@ IPPOOL_RCODE_POOL_EMPTY
#define _IPPOOL_RCODE_DEVICE_MISMATCH
#define _IPPOOL_RCODE_SUCCESS
#define IPPOOL_SPRINT_IP(_buff, _ip, _prefix)
If the prefix is as wide as the AF data size then print it without CIDR notation.
#define IPPOOL_ADDRESS_KEY
static void ippool_action_print(request_t *request, ippool_action_t action, fr_log_lvl_t lvl, fr_value_box_t const *key_prefix, fr_value_box_t const *ip, fr_value_box_t const *owner, fr_value_box_t const *gateway_id, uint32_t expires)
tmpl_t * expiry_attr
Time at which the lease will expire.
fr_redis_cluster_t * cluster
Redis cluster.
static int mod_load(void)
static char lua_update_cmd[]
Lua script for updating leases.
fr_value_box_t pool_name
Name of the pool we're allocating IP addresses from.
static char lua_release_digest[(SHA1_DIGEST_LENGTH *2)+1]
static char lua_alloc_digest[(SHA1_DIGEST_LENGTH *2)+1]
char const * name
Instance name.
fr_value_box_t gateway_id
Gateway identifier, usually NAS-Identifier or Option 82 gateway.
tmpl_t * range_attr
Attribute to write the range ID to.
module_rlm_t rlm_redis_ippool
fr_value_box_t offer_time
How long we should reserve a lease for during the pre-allocation stage (typically responding to DHCP ...
fr_value_box_t gateway_id
Gateway identifier, usually NAS-Identifier or Option 82 gateway.
static unlang_action_t mod_update(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static unlang_action_t mod_bulk_release(unlang_result_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
static unlang_action_t mod_alloc(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
static const call_env_method_t redis_ippool_update_method_env
fr_value_box_t owner
Unique lease owner identifier.
static ippool_rcode_t redis_ippool_update(rlm_redis_ippool_t const *inst, request_t *request, redis_ippool_update_call_env_t *env, fr_ipaddr_t *ip, fr_value_box_t const *owner, fr_value_box_t const *gateway_id, uint32_t expires)
Update an existing IP address in a pool.
fr_value_box_t pool_name
Name of the pool we're allocating IP addresses from.
fr_value_box_t association_time
How long should a device be associated with an IP address.
static unlang_action_t mod_release(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
fr_value_box_t pool_name
Name of the pool we're allocating IP addresses from.
fr_value_box_t lease_time
How long an IP address should be allocated for.
fr_value_box_t gateway_id
Gateway identifier, usually NAS-Identifier or Option 82 gateway.
static conf_parser_t redis_config[]
fr_value_box_t requested_address
Attribute to read the IP for renewal from.
static ippool_rcode_t redis_ippool_release(rlm_redis_ippool_t const *inst, request_t *request, fr_value_box_t const *key_prefix, fr_ipaddr_t *ip, fr_value_box_t const *owner, uint32_t assoc_time)
Release an existing IP address in a pool.
fr_value_box_t requested_address
Attribute to read the IP for renewal from.
fr_value_box_t association_time
How long should a device be associated with an IP address.
static char lua_release_cmd[]
Lua script for releasing leases.
fr_redis_conf_t conf
Connection parameters for the Redis server.
static fr_redis_rcode_t ippool_script(redisReply **out, request_t *request, fr_redis_cluster_t *cluster, uint8_t const *key, size_t key_len, uint32_t wait_num, fr_time_delta_t wait_timeout, char const digest[], char const *script, char const *cmd,...)
Execute a script against Redis cluster.
uint32_t wait_num
How many slaves we want to acknowledge allocations or updates.
static const call_env_method_t redis_ippool_release_method_env
fr_time_delta_t wait_timeout
How long we wait for slaves to acknowledge writing.
bool copy_on_update
Copy the address provided by ip_address to the allocated_address_attr if updates are successful.
fr_value_box_t association_time
How log should a device be associated with an IP address.
tmpl_t * expiry_attr
Time at which the lease will expire.
static char lua_alloc_cmd[]
Lua script for allocating new leases.
tmpl_t * range_attr
Attribute to write the range ID to.
tmpl_t * allocated_address_attr
Attribute to populate with allocated IP.
static ippool_rcode_t redis_ippool_allocate(rlm_redis_ippool_t const *inst, request_t *request, redis_ippool_alloc_call_env_t *env, uint32_t lease_time)
Allocate a new IP address from a pool.
bool ipv4_integer
Whether IPv4 addresses should be cast to integers, for renew operations.
fr_value_box_t owner
Unique lease owner identifier.
tmpl_t * allocated_address_attr
Attribute to populate with allocated IP.
fr_value_box_t gateway_id
Gateway identifier, usually NAS-Identifier or Option 82 gateway.
fr_value_box_t lease_time
How long an IP address should be allocated for.
static int mod_instantiate(module_inst_ctx_t const *mctx)
fr_value_box_t pool_name
Name of the pool we're allocating IP addresses from.
static const call_env_method_t redis_ippool_bulk_release_method_env
static char lua_update_digest[(SHA1_DIGEST_LENGTH *2)+1]
fr_value_box_t owner
Unique lease owner identifier.
static int ippool_wait_check(request_t *request, uint32_t wait_num, redisReply *reply)
Check the requisite number of slaves replicated the lease info.
static conf_parser_t module_config[]
fr_value_box_t requested_address
Attribute to read the IP for renewal from.
static const call_env_method_t redis_ippool_alloc_method_env
Call environment used when calling redis_ippool allocate method.
Call environment used when calling redis_ippool bulk release method.
Call environment used when calling redis_ippool release method.
Call environment used when calling redis_ippool update method.
rlm_redis module instance
#define FR_SBUFF_OUT(_start, _len_or_end)
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
CONF_SECTION * conf
Module's instance configuration.
size_t inst_size
Size of the module's instance data.
void * data
Module's instance data.
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Named methods exported by a module.
#define tmpl_value(_tmpl)
@ TMPL_TYPE_DATA
Value in native boxed format.
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
tmpl_t * tmpl_init_shallow(tmpl_t *vpt, tmpl_type_t type, fr_token_t quote, char const *name, ssize_t len, tmpl_rules_t const *t_rules))
Initialise a tmpl without copying the input name string.
void fr_sha1_init(fr_sha1_ctx *context)
void fr_sha1_final(uint8_t digest[static SHA1_DIGEST_LENGTH], fr_sha1_ctx *context)
void fr_sha1_update(fr_sha1_ctx *context, uint8_t const *in, size_t len)
#define SHA1_DIGEST_LENGTH
eap_aka_sim_process_conf_t * inst
fr_aka_sim_id_type_t type
tmpl_t * lhs
Typically describes the attribute to add, modify or compare.
tmpl_t * rhs
Typically describes a literal value or a src attribute to copy or compare.
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
#define talloc_get_type_abort_const
#define fr_time_to_timeval(_when)
Convert server epoch time to unix epoch time.
static int64_t fr_time_delta_to_msec(fr_time_delta_t delta)
A time delta, a difference in time measured in nanoseconds.
int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert one type of fr_value_box_t to another.
int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
void fr_value_box_bstrndup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Assign a string to to a fr_value_box_t.
#define fr_value_box(_box, _var, _tainted)
Automagically fill in a box, determining the value type from the type of the C variable.
static size_t char ** out